Paul Smith

Announcing gogeos, a spatial data library for Go

Example of geometry processed by gogeos

I am announcing the initial release of gogeos, a library for the Go programming language. gogeos provides spatial data operations and geometric algorithms. While it is a Go library, the hard work is done by the GEOS C library.

The kinds of things you can do with gogeos include:

It also provides interoperability with other spatial data processing systems like PostGIS by decoding and encoding geometries as Well-Known Text (WKT) and Well-Known Binary (WKB).

I started working on gogeos because I looked at the landscape of GIS and spatial data libraries for Go, and found it lacking. Binding to the GEOS library with cgo was a way to get started quickly. Relying on GEOS has its drawbacks, for instance, it creates a large binary dependency, and cgo doesn’t allow for cross-platform compiles.

In the long term, I would like to create a pure Go library that implements functionality such as GEOS and the JTS provide. That would allow for use on platforms that don’t or can’t support C shared libraries, such as Google App Engine, and make it easier for developers to get started working with it.

In the meantime, I hope that gogeos enables more developers who are working with spatial data or GIS to get involved in the Go ecosystem.

gogeos is a fully open-source project, and I welcome contributors and feedback.

@paulsmith

Democratic Party’s voter registration app is now free and open-source software

We (the DNC) have relicensed the Democratic Party’s voter registration application under a standard MIT license, and accompanied the source code with an advisory notice regarding the use of the software. I wanted to explain why we did this.

The Democratic Party initially released the source code to its online voter registration app late last summer, with the intent of making it available for all the standard reasons people and organizations choose when they open-source code: so that it can be improved, so that bugs can be fixed, so others can take it and build further new applications on top of it.

However, it was quickly apparent we had a problem with the open source community. The issue was with the license. It contained a clause that placed restrictions on its use. The reason this clause was included was to address our concerns regarding the highly regulated and closely monitored nature of voting and voter registration. We wanted to avoid a scenario where, either inadvertently or through malice, someone set up a site based on the code, and without following state and federal guidelines and rules, defrauded or disenfranchised a voter. Now, regardless of our good intentions on this matter, the fact that we had taken a standard open source license and amended it with this restrictive clause meant that we did not pass “free and open source” muster, with emphasis on the “free” as in “speech”.

We needed a solution that addressed both the problematic license and our concerns regarding the good-faith use of the software that protected voters. A member of the open source community, Karl Fogel, stepped forward with a proposal: change the license to an unmodified standard OSI-approved license, and include along with the source code an advisory document that outline these legal concerns. The notice would not be binding or otherwise modify the license and therefore terms of use; however, like any piece of open source software, people are “free” to use it illegally, and free to suffer the consequences if they do. The important thing is to remind users of their responsibility to act in accordance with the law, especially when it comes to something as precious and beseiged as our franchise. We feel the combination of a standard FOSS license and a non-binding advisory document expressing the intent of the copyright holder is a way forward for political organizations to release potentially sensitive soure code while at the same time communicating the vital issues animating and conditioning that release.

Now, some observers may not see this as remarkable. There was a bad license, it’s been changed, what’s the fuss? I want to acknowledge the hard work across the organization, from software engineers to lawyers, to find a way to give back to the open source community and satisfy the concerns of both. There are many reasons why organizations don’t release their software as open source. We want to set an example, however small, that there are non-license ways to state any reservations or guiding principles your organization that ordinarily would have prevented a release. Key among these are engaging with the community. As we have learned time and again, good solutions often originate through trust and dialogue.

Lexing Oscar

For the past n years, I’ve built and hosted a web app that lets my film buff friends and me compete by guessing who will win the Academy Awards by voting for nominees in each category. I do a new one from scratch each time. It’s a fun diversion, but it’s also a playground for me to try out new skills picked up in the past year or new tools or techniques I’ve been wanting to fool around with.

The first thing I need to do each time is get a list of that year’s nominees in some machine-readable format. Being a lazy programmer, I’m not going to type in the 100+ nominees into a spreadsheet or text file, so I wind up writing a short throwaway script to coax some list I’ve found online into the form I need for importing. This sort of script is the meat-and-potatoes of the workaday programmer, the ones you whip up in a few minutes as an intermediate step in a larger task. Ordinarily, they’re hardly worth commenting on. They have a vanishingly short half-life, since there is rarely any generality to be derived from them: they only work on the exact input given.

This year, I wanted to try out a new way of getting the nominee list together. Sure, for a small task like this, there’s no compelling reason not to go with the same kind of quick throwaway script as before. But again, the point of the Oscars app is to exercise new or different muscles.

My goal was to generate a representation of the list of nominees in a format such as CSV suitable for importing into a database. I found a source list of nominees, formatted as follows: the name of the category is on the first line, then a list of nominees comes next, each requiring two lines, one being the name of the film and the other a name or list of names associated with the nomination, all followed by a blank line, then the subsequent category starts on the next line and we repeat. I wanted to read in and parse text formatted like this:

Directing
Amour
Michael Haneke
Beasts Of The Southern Wild
Benh Zeitlin
Life Of Pi
Ang Lee
Lincoln
Steven Spielberg
Silver Linings Playbook
David O. Russell

Actor in a Leading Role
Lincoln
Daniel Day-Lewis
…

And convert it to this:

Directing,Amour,Michael Haneke
Directing,Beasts Of The Southern Wild,Benh Zeitlin
Directing,Life Of Pi,Ang Lee
Directing,Lincoln,Steven Spielberg
Directing,Silver Linings Playbook,David O. Russell
Actor in a Leading Role,Lincoln,Daniel Day-Lewis

Normally, to scan and parse this type of input, I would write a program to loop over each line of the input, with a number of global state variables, keeping track of what tokens I was currently processing. In this case, I might have global state variables indicating whether I was currently processing a category and what the current film is, and I would have a set of if/elif/else statements for tests of various combinations of those variables, including for the contents of the current line (a blank line or EOF indicating the end of a category).

Each time through the loop, then, we get a line from the text and check to see what state we’re in. While this approach is easy to get started with, it leads to fragile code and requires a lot of mental bookkeeping. Worse, each time through the loop, the state of where we are and what we just did is forgotten. That accounts for the proliferation of state variables to be checked in order to restore the state of the processing. Think about it, we are marching sequentially through this text, wouldn't it be nice if we could just pick up where we left off with the last action?

My approach this time is inspired by Rob Pike’s talk on lexical scanning. Instead of a loop where we get the next bit of text to examine and restore the state of the processing by examing a number of state variables, we instead have a loop where a function is called that returns the next function to be called. In other words, a function is called which does a bit of processing of the text, advancing the pointer or consuming from a stream, maybe emitting some tokens, and then returns to the caller the function that should proceed from where the returning function just left off. For instance, we just scanned a category, which means we know we are ready to scan a film, so call the film scan function. That next function can just carry on its processing without any state-checking preliminaries. The loop of our system therefore is very concise, just calling functions and getting the next one to call the subsequent time around. Roughly:

def run():
    state = start_state
    while state:
        state = state()

When we are done processing input, say, EOF is reached, the state function currently executing can return None to the caller, which will end the while loop and shut down the machine.

The advantage to the programmer is that instead of building up a complicated switch of control to determine what state our machine is in, we simply write functions that proceed naturally from the last state, and then hand off control to the subsequent function. It’s clean and helps keep the complexity of the system manageable. Any time you can reduce the number of control flow statements and replace them with simple functions is a win in my book.

So back to the Oscars. This year, I opened the official nominee list from the Academy’s site, a PDF. I selected the text, copied and pasted it into a text document. The only manual editing I did was to add a blank line between each group of nominees by category, and I also joined lines in categories like Music (Original Song) where the title of the song and the name of the composer is split across multiple lines—these were quick changes that simplified the scanning logic.

There are three state functions in my program, one for each of category, film, and name (or list of names):

def lex_category(lexer):
    lexer.emit(CATEGORY, title(getline()))
    return lex_film

def lex_film(lexer):
    line = getline()
    if line == '':
        lexer.emit(BLANK, '')
        return lex_category
    elif line is None: # EOF, shut down lex machine
        return None
    lexer.emit(FILM, title(line))
    return lex_names

def lex_names(lexer):
    lexer.emit(NAMES, title(getline()))
    return lex_film

(title() handles some odd case formatting in the source text by converting strings to title case.)

lex_film is the most complex, having to handle the possibilities of a blank line, meaning we’re moving on to the next category, EOF, which shuts down scanning, and the film itself. But in all cases we merely return the next state function to called (or None).

Admittedly, this is more sophistication than normally appears in my yearly nominee list parsing. But I have to say that I was able to write the program in about the same amount of time, found it ran correctly the first time, and was actually kind of fun to do. And while this was a silly example, you can start to see the power you can get from this approach when lexing different kinds of input with more and more complex tokens. When you lift the flow of control up a level and let your functions focus on the task at hand, the result I think is a more elegant and more obviously correct program.

The script and input text are here, and the output list of nominees is here.

The Election Day Advent Calendar

The Election Day Advent Calendar

My friend Ben Helphand and I started scheming in 2005 on a way to celebrate the right to vote. We believed that a great nation deserves great civic rituals, and the election season was the natural time for such a ritual. What we came up with was the Election Day Advent Calendar for 2006. The idea was simple: inspired by the traditional Advent calendar for Christmas, our calendar let you open a door a day through Election Day, and reveal interesting facts and quotes about our democracy and the history of voting. It would be non-partisan but not scrubbed of parties, a reflection on the many events and people that comprise the story of the franchise.

We wanted to make a real calendar that you could buy and hang up. Neither of us had any experience in the print production world, and we both had day jobs in different fields. We had to figure out all the steps of the process, from hiring an artist to forming an LLC to sales and shipping and marketing. We put up our own money to fund it, and hoped to sell enough just to break even.

The response to that first Calendar was strong, and told us there was a desire for such products that let us all celebrate the shared history of American politics. People were delighted by the concept; when they saw it, they got it. We heard from teachers that it made a great part of their back-to-school civics lesson plans, and from many people who said they gave it out as a gift to a politics-nerd friend or colleague.

After repeating the process in 2008, we took a break in 2010 but didn’t give up on the core idea. What we needed, though, was a different approach to paying for production—it was just too risky to put up our own money time and again. In the meantime, along came Kickstarter. It’s perfect for a project like ours.

As I write, there are 6 days remaining in our campaign, and we’re a little more than half way to our goal. If you’re reading these words and like what I’ve described, please support our Kickstarter.

Our motto with Gerrymander, the small company Ben and I founded for the Calendar, is “Make Small Plans”. It’s a gently mocking riff on Daniel Burnham’s famous and possibly apocryphal quote. Our republic, as great and large as it is, is still composed of the small democratic actions of all of us, and those things require care and feeding, and they ask to be done well. If the Election Day Advent Calendar provides civic nourishment in any way, then it will have been a success.

Interview: Mike Migurski

Mike Migurski is partner and Director of Technology at Stamen design studio in San Francisco. He and his Stamen colleagues recently unveiled a new site, maps.stamen.com, that included three custom-rendered maps using data from OpenStreetMap, including a remarkable one that, despite being generated by algorithm from precise vector data, resembled a hand-made watercolor painting.

Paul Smith

You’ve blogged about the process of creating the Terrain map tiles, and the code for the Toner tiles is open-sourced and on GitHub, but the Watercolor tiles seemed to come out of the blue. Can you talk about what inspired them, how you and your Stamen colleagues went about designing them, and what uses you imagined for them?

Mike Migurski

The main use we imagined for them was that they would look really, really good, and unlike anything else being done with online maps. The process started with Eric Rodenbeck and Zach Watson kicking around some ideas on simulating the appearance of watercolor painting algorithmically, and expanded to include Geraldine Sarmiento’s hand-done textures.

We saw an amazing reaction to Aaron Straup Cope’s work on Prettymaps last year, and more generally a lot of interest in map-based art, so it seemed natural to try something that was algorithmic and at the same time had the appearance of being made by hand. I figured people would swallow their tongues in surprise when they saw these, especially when we switched from image search results for painted textures to pictures we were making ourselves for the project.

PS

Making maps these days is often about mechanizing the conversion of vector data, like from OSM, into raster images, which has meant perfecting our ability to layer and style points, lines, and polygons in very precise ways. I think what captivated people about the Watercolor tiles is that they seemed to color outside the lines, so to speak, in a way that didn’t seem possible with current tools. What tools did you use to generate the tiles, and how did you engineer them in a way to achieve this effect? Did you have to write new software to aid you?

MM

We did write new software, yes. We’ve been exploring ways to make OSM data more usable by cartographers over the past few years, and that’s largely been expressed in code designed to make large data sets easier for cartographers (and ourselves) to deal with:

  • Cascadenik was the first widespread application of CSS-like style rules in this area, since developed and expanded by Development Seed in Carto.
  • TileStache is a tile-generation server built to deploy custom visualization and rendering code.

I’ve been talking about this stuff for a few years, and the release of maps.stamen.com is intended to be a showcase that helps shift expectations of what good, online cartography should look like. It hasn’t been long since using a solid anti-aliased vector-rendering library like Mapnik was enough to make a strong showing against commercial map providers, but now we’re starting to establish new ideas around texture, color and labeling that require a layer of additional work beyond Mapnik.

Watercolor itself is a custom Provider to TileStache, feeding on simple Mapnik output and adding techniques like gaussian blur and Perlin noise as well as high-quality scans of actual water color paintings to achieve its effect. The development of watercolor had a number of stages, beginning with Zach’s experiments in noise and texture, Eric and George Oates’s encouragement, Geraldine’s addition of color and texture, and proceeding to my work with Jeff Easter and Nathaniel Kelso to improve performance until the code was good enough for public launch. The visual appearance is ridiculously CPU-hungry compared to your typical vector cartography, so we’ve got a few virtual servers on the moon doing the live calculation of new maps in new places.

Without diving too deeply into the actual watercolor code, we owe a lot to Kai Krause’s Algorithmic Painting ideas from almost 20 years ago.

PS

I see that Stamen is releasing these tiles under a Creative Commons license as part of a Knight Foundation-funded project centered around data visualization and cities. City governments are historically big users of enterprise GIS software like ArcGIS; are there any lessons here for government or citizens, or does the work, specifically the Watercolor tiles, speak for themselves as art?

MM

I think the latter: watercolor is basically art. Of course there’s an undeniable political component to the OpenStreetMap data it’s made of. In the U.S. OSM Foundation we’re interested in ways to get government at various levels to participate custodians of OSM, and I think open data and enterprise GIS software can cooperate. Esri puts a lot of effort into OpenStreetMap-related efforts, and I’m not expecting to see their involvement in city governments wane.

PS

Can you expand a bit on the interplay of vector data, raster data, and image filters to produce the tiles? What sort of preliminary work did you need to do to get the components parts to fall into place? Do you see patterns emerging and opportunities for abstraction for future artist map tools?

MM

I probably can’t explain as well as Zach just did.

As a bystander to this part of the process, it seemed like the actual simulation technique took shape in just a few days, based on Zach’s existing experience with image manipulation in Python. The real work came in the knob-twiddling, or as we call it internally, “spring tuning” (based on our experience with the Digg Swarm project from 2007). Here, for example, is one of Zach’s own parameter views that he used to tune noise thresholds for the ground texture.

I think the pattern that’s emerging for me is the raw labor-intensivity of this kind of work, the parameter-tweaking in a space of possible outcomes that results in something that looks right and feels exciting. Once the basic structure of noise, blur and threshold is in place, all you can really do is watch carefully as you repeatedly try combinations until something clicks.

PS

We’re usually talking about algorithms and stylesheets when we talk about web maps. Traditional cartographers often exercise artistic license over data streams as well—for example, manually but subtlety tweaking the curve of a road so that it reflects a shared or colloquial understanding of its location rather than it’s literal location. And then there are the more abstract but functional examples like subway system maps, whose stops and lines are not intended to be scale representations of their real-world counterparts. Do you see it possible for automated cartography to produce maps like these? What techniques would we need to develop (for example, a “hints” file ala typography for manually overriding certain points)?

MM

I’ve not yet seen an attempt at automating this kind of cartography which has resulted in a satisfying outcome, but it’s still the subject of many PhD theses, so maybe it’s just too early. I suspect that we’ll end up seeing is a companion project to OSM where human make decisions about how things should be shown and contribute those to a free and open data source. Everything is still so manual in this world, and the subject of most maps doesn’t move around all that much, so you can really apply a human eye to get it right. Even with the watercolors, we had to do a lot of manual work to ensure that the 1024×1024 watercolor texture blended cleanly and the various road sizes looked correct at each zoom level.

PS

Regarding deployment. One of the challenges of producing raster map tiles for the web is the amount of storage and CPU time it takes to generate them; I notice that Stamen’s tiles are available down to zoom 18, which for a worldwide set means there are millions and millions of individual PNG files. To a degree CPU time can be amortized over the life of the project if you’re using a tile server to dynamically generate and cache tiles as users first request them, but even with commodity storage like S3, you’re talking about hundreds of GB or more. Are there knock-on challenges this presents for deployment and maintenance? Is there a sustainability plan for maps.stamen.com with regard to storage and bandwidth costs, or is Stamen as a company just going to eat those costs to provide this resource?

MM

We’re using a mix of physical and virtual machines for each of the tile sets we just released, blending the strengths and weaknesses of each. The CPU-intensive rendering of watercolor maps is done on Amazon EC2 where we can invoke extra machines as necessary, but the PostGIS, Mapnik and cache storage parts are all living on an actual server in a colocation facility. We decided last year to invest in physical hardware to take advantage of the high random-access speed of solid state disks, which make it possible to serve the entire OpenStreetMap planet database without incurring the overhead of Amazon’s terribly slow I/O speeds.

Fortunately, the back-end of this project is used to drive a lot of our other work, so we’re folding the cost into a series of different engagements that all use different components of the map tiles.

PS

We appear to be reaching a tipping point where rolling your own custom map stack seems not only practical but desirable for many applications. What is your reaction to the embrace of OSM by prominent technology companies, and the emergence of designer-friendly tools like TileMill? Do we have everything we need for most designers and developers to create the map experiences they want to provide? What tools would you’d like to see built; what data sets made available?

MM

Honestly, I’m completely thrilled. With this year’s high-profile addition of Foursquare and Apple to the OpenStreetMap community, I’m looking forward to seeing what new artists and designers decide to do with maps—I can’t wait for the U.S. State Of The Map conference this autumn.

I think there are two issues that current tools don’t address well enough, and I’m excited to be working on them both: medium-scale data for counties and towns, and more options for bitmap filtering and output. I want Photoshop and Illustrator in the sky, essentially, and tools like TileMill help expose places where we need to be doing more with data before rendering and more with pixels after rendering.

PS

Elaborate on what you mean by “medium-scale data”, and how it would improve map-making.

MM

My colleague Nathaniel Kelso runs a project called Natural Earth Data, which offers global vector data at three different scales, optimized for rendering images of large regions, countries and continents, up to about zoom=9 if you think in terms of web slippy maps. OpenStreetMap meanwhile offers small-scale data down to the level of individual carriageways on major streets. There’s a gap between these two data sets where OSM is too detailed and Natural Earth is not detailed enough, so on many renderings you get bizarre selections of town names to render, doubled-up street names, or no global context.

The Terrain layer on maps.stamen.com is a vehicle for exploring a few avenues through this problem: feature generalization for route shields and large street names using the Skeletron library, simulated annealing for smarter label placement with Dymo, and cross-blending of raster data sets for ground cover and hill shading. We’re doing a lot of work to make OSM data better for rendering, and releasing all the component parts as software for processing data sets.

PS

Do you see Mapnik as the appropriate place to grow the bitmap filtering and output functions?

MM

As far as Mapnik’s role in all this, I think it’s the single best place to do vector rendering, but I’m looking elsewhere for filtering and output. I prefer to use tools that are specialized for individual tasks, so we use the pixel output of Mapnik as a source for Python-based pixel manipulation code, often implemented in libraries like NumPy that offer rapid manipulation of bitmap arrays.

PS

It sounds like you’re hinting at a new program for this kind of manipulation. You and Stamen have contributed a great deal of open-source map making software over the years; will the code that created Watercolors be released?

MM

I hope I’m not sounding too coy; there’s not any secret piece of software running the show, just a set of well-known techniques in a new arrangement. I’ve released everything I’ve ever started, but my role in Watercolor was more about taking something that already worked and making it work a little better so more people could see it.

PS

Most web maps are a pre-baked set of raster images assembled in the viewport of the browser—do you see this fundamental arrangement changing in the foreseeable future? With WebGL and HTML5 Canvas, are we ready to composite maps client-side with servers pushing vectors data over the wire? What tradeoffs are there here? Do you think you could do Watercolors entirely in the browser anytime soon?

MM

I don’t think we’re far off, though there are a few impediments still in the way. Much of the core functionality of Watercolor’s bitmap effects can be implemented entirely on a GPU in a WebGL fragment shader, so there’s no reason that we couldn’t build it that way. As far as shipping vectors, I’d love to see it happen. It’s actually not unrelated to the work we’re doing with differently-scaled data: you want your underlying data to be at the “right” level of complexity, and that generally means modifying it in some way, by dropping extra points, scrunching narrow polygons into lines, making small things disappear, and lumping groups of things together into single blobs. If we can figure out a better way to simplify on the fly, then complete client-side rendering could be a reality. Of course, Google has already done a lot of this themselves, but it’s different when the open source community does it and shares the results and the research.

PS

Simplification of lines and polygons is a common need for mapping projects, not only for display but also for interaction—clients can only handle so many points during the refresh cycle. It can be a big challenge for workflows to simplify vectors, and also to preserve topology, the relationship between shapes—our model is of disconnected points, lines, and polygons. That’s one reason I’m excited about topology as a type coming in PostGIS 2.0. What simplification techniques should we be using and exploring, both on the algorithm side as well as the workflow side?

MM

I spent about two years (off and on) researching line generalization. Skeletron went through three iterations, starting with a port of the straight skeleton technique from Tom Kelly’s description, to a collaboration with Schuyler Erle binding to the CGAL library from Python, finally settling on an application of the Voronoi diagram first published by Esri in 1996. All the way through, I kept thinking that there just had to be an easier way to make simple lines out of complex ones, and why wasn’t I finding code to do it for me? The simplification techniques we should explore are all known and published, but exist largely as plugins for systems like ArcGIS, instead of chainable tools in the Unix style. PostGIS 2.0 is going to help in a big way, and I hope that some of that effort migrates out to tools for managing workflows around flat files.

If all goes well, it should start to make sense to ship vectors over the wire and render them on the client.

It’s an interesting question to me whether client-side rendering really something we want to aim for, though. Bitmap tiles have an equilibrium of performance, size and design that I don’t think will be disturbed any time soon. I’m learning what I can about GPUs to be ready when the day comes, but in the meantime most of my focus is on developing workflows for data. OSM extracts are one aspect of this; simplifying OSM data and standing up fresh new rendering databases from source data is another. The scaffolding that makes life easiest is a combination of bias toward flat files and Postel’s Law: don’t screw around with “seamless” servers, publish data flat using old file formats, and only invent brand new things when they’re needed. Spherical Mercator slippy map tiles are fast becoming one of those well-understood old file formats, so this is what we’ve aimed for with Watercolor; otherwise, how could we have a section on maps.stamen.com showing how to use the imagery in your own applications?

PS

That’s interesting—so are you generally fine with the way Spherical Mercator has colonized the web map world? It seems to have been a decision purely about tradeoffs: what projection “works” for world-wide maps all the way down to zoom level 22, or however detailed Google Maps gets these days. But clearly choice of projection is a never-ending debate. Is Spherical Mercator an acceptable enough constraint, from your perspective, within which to do the kind of artistic expression Stamen does, and maintain interoperability?

MM

Oh yeah, I’m absolutely fine with it. It’s one of those “assume a spherical chicken” engineering solutions that actually leads to so much follow-on innovation that in retrospect I’m glad no one was letting the cartographers drive at Google in 2005. Projections only matter when you’re looking at large areas, and that’s really not the case when you’re searching for driving directions or checking out the neighborhood where you spent elementary school. It’s interesting to me, though, that the typical fifty states map you see on every link bait infographic out there is based on a conic projection—it’s about what looks right for a genre of mapmaking, and in the case of slippy maps the Spherical Mercator is clearly the obvious choice.

@paulsmith

Going to work for Democrats

I have some exciting news: in a couple of weeks, I will be the new deputy director of technology at the Democratic National Committee. I’ll be helping to create software that helps get Democrats elected. It’s a great opportunity for me to do what I love for an organization that I passionately support. I hope to help make the technology department there top-notch in terms of software engineering practices, bringing what I’ve learned from having helped develop, deploy, and grow EveryBlock. And I’ll have some projects of my own, which will hopefully advance the state of campaign software somewhat. It’s especially exciting, too, to be able to collaborate with friends in Chicago working on that one campaign.

I have been volunteering on political campaigns—federal, state, and local races—for years, and have often lamented the state of campaign software. It’s partly understandable, because campaigns tend to be all-hands-on-deck, hair-on-fire affairs, where it’s hard to justify long-range planning and software development, even if it might make the lives of your staff, organizers and volunteers easier, since your organization may not even exist for more than a few months. And campaigns rarely have in-house software engineers, so opportunities to capture and encode knowledge in the form of software, and explore new technologies, are missed.

Obama For America gets this—that’s why they’ve hired like a start-up for this campaign cycle, recognizing that great software is a competitive advantage and no longer an afterthought you contract out for. And the DNC gets it, too, and that’s why I’m excited to join them. The chance to help re-elect this president, restore Democratic majorities in Congress, and also to help down-ballot Democrats across the country in this and future campaign cycles is one I couldn’t pass up.

I’ll be commuting to the DNC’s offices in Washington, D.C. from Baltimore on a regular basis, though I’ll still be working from home a couple of days each week, so that I won’t too miss much of this kind of stuff.

It’s a bittersweet development, because I’ll be leaving EveryBlock, which I helped found 4 years ago. With the success of the recent relaunch, though, I feel now is as good a time as any to step away. The site is in great hands, and the response from users to the new version has been enthusiastic. It couldn’t have a better home than msnbc.com, who have provided great guidance and resources. I’m thrilled with the success we’ve had and for how far it’s come, and I’m confident that it will continue to be the best place on the internet to help make your block a better place.

I am particularly grateful for having worked with my great EveryBlock colleagues. I’m humbled by them and their talents and work ethic. It was a privilege to learn from them and improve my craft, however modestly, by their examples.

For now, I’m focusing on winding down at EveryBlock, and getting prepared for a new commute (I’ll try to hack it with the MARC train and a bike) and a campaign season now fully engaged. It’s a thrilling opportunity, and I hope to make the most of it.

@paulsmith

Maxine

P1040879.jpg

One month ago today, Maxine Mills Smith arrived in this world. Her mom gave birth to her at Mercy Medical Center in Baltimore, Maryland, at six in the morning. She was, and continues to be, a long and strong gal. She enjoys being carried about and looking up at the changing scenery. Like her father, she zonks out to the motion of a vehicle ride, be it stroller or car. She has healthy lungs, likes to exercise them, and is a vocal chirper. She has been respecting her mom and dad with 5 and 6-hour stretches of sleep at night, but likes to mix it up from time to time and throw her mom some napless curveballs. When she is awake, she is bright and alert. Given the choice, she’d rather have some light assistance and try to stand and monster march (I said she was strong) than squirm around on her belly like a beetle. Her binky is a frequent companion, and she is a champion eater of mom’s milk. The doctors and nurses at the pediatrician’s office think she is doing fine, and give her an extra wink. We think she’s is doing fine, too. Family love Maxine. Welcome home, my daughter.

Parsing and formatting date/time in Go

Go takes an interesting approach to parsing strings to time objects, and formatting time objects as strings. Instead of using codes like most languages to represent component parts of a date/time string representation—like %Y for a 4-digit year like “2011” or %b for an abbreviated month name like “Feb”—Go uses a mnemonic device: there is a standard time, which is:

Mon Jan 2 15:04:05 MST 2006  (MST is GMT-0700)

Or put another way:

01/02 03:04:05PM '06 -0700

Instead of having to remember or lookup the traditional formatting codes for functions like strftime, you just count one-two-three-four and each place in the standard time corresponds to a component of a date/time object (the Time type in Go): one for day of the month, two for the month, three for the hour (in 12-hour time), four for the minutes, etc.

The way you put this into action is by putting together the parts of the standard time in a layout string that matches the format of either the string representation you want to parse into a Time object or the opposite direction, when you want to generate a string representation from an Time object.

Parsing:

package main

import (
    "fmt"
    "time"
)

func main() {
    value  := "Thu, 05/19/11, 10:47PM"
    // Writing down the way the standard time would look like formatted our way
    layout := "Mon, 01/02/06, 03:04PM"
    t, _ := time.Parse(layout, value)
    fmt.Println(t)
}

// => "Thu May 19 22:47:00 +0000 2011"

Formatting:

package main

import (
    "fmt"
    "time"
)

func main() {
    t := time.SecondsToLocalTime(1305861602)
    t.ZoneOffset = -4*60*60
    fmt.Println(t.Format("2006-01-02 15:04:05 -0700"))
}

// => "2011-05-20 03:20:02 -0400"

There are predefined constants in the time package for common formats such as RFCs 822 and 3339.

The use of a mnemonic over obscure formatting codes I think reflects the pragmatism of Go’s developers and their focus on creating a language that makes its users more productive. While it is a break with tradition to abandon strftime-style formatting, they probably recognized that most developers, no matter how experienced, reach for man strftime or similar documentation more often than not (hell, I have a mug with the codes printed on it), and each time they do, it is an expensive context switch, in terms of lost focus. Writing the standard time down the way yours looks may be quirky, but it's easy to recall, and it also happens to match the shape of your time string, syntatically.

It’s fascinating to see a language with the pedigree of Go—from the minds of long-time C and Unix developers—toss aside certain old and venerable ways of doing things. But it’s consistent with a language that’s relatively small (in the good way of being comprehensible and coherent), focused on efficiency, and careful in what it includes.

A partial list of metaphors, visual and otherwise, anti-skeuomorphism zealots have to tackle to reach utopia

icons Motivated by irrational hatred and overstated claims of the continuing utility of a 3.5" floppy disk icon to mean “save”:

Of course there are many, many anachronistic interface elements and metaphors in the world, and we get by okay. Mainly, this is because new generations don’t suddenly appear next to us and start using our computers without any foreknowledge of the metaphorical items. They spend time learning with the old fogeys for whom information was sometimes stored inside square pieces of plastic and metal. This overlap is necessary in general because knowledge about tools is not encoded in our genetic material. All understanding of use is part of a multi-layered strata of culture, experience, and relationships.

The real problem anti-floppy-disk people have is explaining a harm, specifically, a harm that matters. Often when we think of user interface improvements that matter, we think of examples like improving medical devices to reduce user error, changes that literally save people’s lives. Or tweaks to software that improve user efficiency and productivity, saving money. It’s hard to conceive of what might be improved by finding a better metaphor for “save” other than some designers’ personal sensibilities.

More Redis internals: Tracing a GET & SET

In my previous article, I took a superficial look at how Redis starts up and prepares itself to process commands. In this article, I'll follow a GET and a SET command as they move from client through the server and back. The GET will be for a key that doesn't exist, and the SET will set that key. Then I'll look quickly at a subsequent GET and how it differs.

As before, I'm exploring Redis with the source code open in my editor and indexed with a tags file, and the Redis server running under gdb in another terminal.

Caveat: this article was written against the codebase of Redis 2.2.1. With respect to my previous article, for a list of what has changed in Redis since I wrote it, see this comment on HN.

Edit: I made two minor changes based on feedback—Redis keys are not Redis objects, they are sds strings; and you don’t have to hack the Makefile to compile without optimizations.

GET

Let's execute the command get users:1234 on Redis.

Preparing

If you inspect certain variables under gdb, you might not get what you want. Instead you see a message like "." This is because the compiler has optimized the machine code in such a fashion that the portion of memory you wanted to look at that was never used, at least for the variable under inspection. To make stepping through the code and inspecting a little easier, we make sure that Redis is not compiled with optimizations. You can do this by either building Redis with the following invocation:

make noopt

or by setting an environment variable:

OPTIMIZATION= make

Sending the command from the client

If we look at the repl loop of redis-cli, we see that it uses the linenoise library to split the arguments of the command. It dispatches on the first argument. The loop checks for client commands that aren't processed as a command by the Redis server, like exit/quit, clear (to clear the screen), and connect (which is a way to connect to a specified Redis server on host port, instead of the default host of 127.0.0.1 and port of 6379.

Any other argument is considered the name of a command to send to the server. The remaining arguments are the arugments for that command.

We're trying to get the on-the-wire representation of the get users:1234 command. redis-cli uses a redisContext struct to encapsulate the state of the connection to the server, as well as the output buffer where the command in the form of the Redis protocol is written for sending to the server. We know from reading the source of hiredis (the Redis C client library that the redis-cli program is built on) that the obuf field is where the raw command is stored:

# hiredis.h:107
/* Context for a connection to Redis */
typedef struct redisContext {
    int fd;
    int flags;
    char *obuf; /* Write buffer */
    int err; /* Error flags, 0 when there is no error */
    char *errstr; /* String representation of error when applicable */

    /* Function set for reply buildup and reply reader */
    redisReplyObjectFunctions *fn;
    void *reader;
} redisContext;

If we set a breakpoint on cliReadReply, we can inspect the output buffer and see exactly how the command looks as a bytestring bound for the server.

client $ gdb src/redis-cli
(gdb) b cliReadReply
(gdb) run
Starting program: /home/paul/src/redis-2.2.0-RC2/src/redis-cli 
Reading symbols for shared libraries +. done
redis> get users:1234

Breakpoint 1, cliReadReply (output_raw_strings=0) at redis-cli.c:421
421         if (redisGetReply(context,&_reply) != REDIS_OK) {
(gdb) p context->obuf 
$1 = 0x100102428 "*2\r\n$3\r\nget\r\n$10\r\nusers:1234\r\n"

We see that the Redis command get users:1234 as entered in our client is translated to *2\r\n$3\r\nget\r\n$10\r\nusers:1234\r\n. Any Redis client is going to convert our command expressed in its respective syntax to the same on-the-wire format. So in Python:

>>> redis_client.get('users:1234')

will send the same *2\r\n$3\r\nget\r\n$10\r\nusers:1234\r\n bytestring to the server.

Let's print that bytestring to screen and render those `\r\n's as line feeds so we can see an expanded view and get a better look at the protocol.

*2
$3
get
$10
users:1234

The first bit is *2, which tells us that the arity of the command, including the command name, is 2. That is, the server should expect two arguments to follow.

The next bit is $3, which means that the length of the first argument in bytes is 3. The argument itself follows, our command name, get.

The next bit after that is $10, so the length in bytes of the second argument is 10. Our one and only argument to the command is next, users:1234, the key we are trying to get.

Receiving the command on the server

If you remember from the last article, readQueryFromClient is a good place to set a breakpoint in your debugger on the server side for inspecting an inbound client command.

server $ gdb src/redis-server
(gdb) b readQueryFromClient
Breakpoint 1 at 0x100011445: file networking.c, line 882.
(gdb) run redis.conf
Starting program: /home/paul/src/redis-2.2.0-RC2/src/redis-server redis.conf
Reading symbols for shared libraries +. done
[63700] 01 Mar 11:04:40 * Server started, Redis version 2.2.1
[63700] 01 Mar 11:04:40 * The server is now ready to accept connections on port 6379

Now back in the terminal with the client running in the debugger, continue to send the command to the server, which will stop at the breakpoint we set.

# client
(gdb) c
Continuing.

# server
Breakpoint 1, readQueryFromClient (el=0x100200000, fd=5, privdata=0x100804e00, mask=1) at networking.c:801
801     void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {

Let's step to the following line:

# src/networking.c:808
nread = read(fd, buf, REDIS_IOBUF_LEN);

If we step to here in our debugger, we see that the server read 30 bytes. If you count the number of bytes in our Redis protocol-encoded command, *2\r\n$3\r\nget\r\n$10\r\nusers:1234\r\n, you'll see it's 30. Just for good measure, let's look at the 30 bytes beginning at the memory location pointed to by buf:

(gdb) p nread
30
(gdb) x/30cb buf
0x7fff5fbfeaf0: 42 '*'  50 '2'  13 '\r' 10 '\n' 36 '$'  51 '3'  13 '\r' 10 '\n'
0x7fff5fbfeaf8: 71 'G'  69 'E'  84 'T'  13 '\r' 10 '\n' 36 '$'  49 '1'  48 '0'
0x7fff5fbfeb00: 13 '\r' 10 '\n' 117 'u' 115 's' 101 'e' 114 'r' 115 's' 58 ':'
0x7fff5fbfeb08: 49 '1'  50 '2'  51 '3'  52 '4'  13 '\r' 10 '\n'

And we can see our whole command bytestring is there, byte by byte.

The server has now read in the entirety of our command in one step. (Because we had a relatively short command, one that fits inside a kernel buffer, and we are the only client on a loopback network device, this is the case, but it need not be. Since Redis is event-driven, this function, readQueryFromClient, is called whenever there are bytes from buffers to be read. If our command was particularly long, or there was a lot of network contention, the command may take more than one I/O event before it is fully read. For this reason, Redis builds up a buffer per client and appends bytes to it on each call to this function. It only proceeds with processing the command when it has been fully read. But we don't need to consider this in our simple example, so we will proceed.)

We're going to elide the processing of the input buffer. This is the point where the server takes the Redis protocol-encoded bytestring of our request and unpacks it into arguments on the client struct object. If you are interested in the details of that parsing, examine the function processMultibulkBuffer in networking.c. All we are interested in at this point is that the argc member of the client object is the number of command arguments (counting the command name itself) and argv is a pointer to the list of arguments.

The bit of code we care at this point is processCommand. The first thing the server does is look up the command in its command table (see "Setting up command table" in the previous article, but note that this lookup is now O(1), see the HN thread linked above). Assuming the command is found (which our get will be), the server will double-check that the arity of the command as defined in the command table matches the number of arguments received from the client (c->argc).

# redis.c:998
cmd = lookupCommand(c->argv[0]->ptr);
if (!cmd) {
    addReplyErrorFormat(c,"unknown command '%s'",
        (char*)c->argv[0]->ptr);
    return REDIS_OK;
} else if ((cmd->arity > 0 && cmd->arity != c->argc) ||
           (c->argc < -cmd->arity)) {
    addReplyErrorFormat(c,"wrong number of arguments for '%s' command",
        cmd->name);
    return REDIS_OK;
}

Skip down to the end of processCommand. Because our humble get is not a "multi" command like mget, mset, etc., it doesn't require queue-like processing of the underlying multiple commands, so we go right to call, which is where our command is dispatched.

# redis.c:953
void call(redisClient *c, struct redisCommand *cmd) {
    long long dirty;

    dirty = server.dirty;
    cmd->proc(c);
    dirty = server.dirty-dirty;

    if (server.appendonly && dirty)
        feedAppendOnlyFile(cmd,c->db->id,c->argv,c->argc);
    if ((dirty || cmd->flags & REDIS_CMD_FORCE_REPLICATION) &&
        listLength(server.slaves))
        replicationFeedSlaves(server.slaves,c->db->id,c->argv,c->argc);
    if (listLength(server.monitors))
        replicationFeedMonitors(server.monitors,c->db->id,c->argv,c->argc);
    server.stat_numcommands++;
}

Let's focus on line 952, cmd->proc(c);. This is Redis's dynamic dispatching of command function calling. Redis makes this clean and simple by encapsulating commands and giving all the actual underlying command functions the same function signature, taking our client object, which carries the payload of our command's arguments. So we're interested in looking into the details of the Redis command object and the actual function that will handle our get.

# redis.h:504
struct redisCommand {
    char *name;
    redisCommandProc *proc;
    int arity;
    int flags;
    /* Use a function to determine which keys need to be loaded
     * in the background prior to executing this command. Takes precedence
     * over vm_firstkey and others, ignored when NULL */
    redisVmPreloadProc *vm_preload_proc;
    /* What keys should be loaded in background when calling this command? */
    int vm_firstkey; /* The first argument that's a key (0 = no keys) */
    int vm_lastkey;  /* THe last argument that's a key */
    int vm_keystep;  /* The step between first and last key */
};

If we pop up to the top of redis.c, we see the definition of the Redis command table, and our get is the first entry.

# redis.c:71
struct redisCommand readonlyCommandTable[] = {
    {"get",getCommand,2,0,NULL,1,1,1},

getCommand is the function that does the actual work for our command. It's a thin wrapper for getGenericCommand.

# t_string.c:62
int getGenericCommand(redisClient *c) {
    robj *o;

    if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL)
        return REDIS_OK;

    if (o->type != REDIS_STRING) {
        addReply(c,shared.wrongtypeerr);
        return REDIS_ERR;
    } else {
        addReplyBulk(c,o);
        return REDIS_OK;
    }
}

void getCommand(redisClient *c) {
    getGenericCommand(c);
}

The arguments to lookupKeyReadOrReply are the client object, the key users:1234 we're trying to look up, and an object, shared.nullbulk that will be the default reply to the client if the key is not found.

# db.c:58
robj *lookupKeyReadOrReply(redisClient *c, robj *key, robj *reply) {
    robj *o = lookupKeyRead(c->db, key);
    if (!o) addReply(c,reply);
    return o;
}

lookupKeyRead is a thin wrapper for lookupKey that handles removing keys that have been set to expire.

Now we get to the heart of the get command -- looking up the key in the database.

# db.c:9
robj *lookupKey(redisDb *db, robj *key) {
    dictEntry *de = dictFind(db->dict,key->ptr);
    if (de) {
        robj *val = dictGetEntryVal(de);

        /* Update the access time for the aging algorithm.
         * Don't do it if we have a saving child, as this will trigger
         * a copy on write madness. */
        if (server.bgsavechildpid == -1 && server.bgrewritechildpid == -1)
            val->lru = server.lruclock;

        if (server.vm_enabled) {
            if (val->storage == REDIS_VM_MEMORY ||
                val->storage == REDIS_VM_SWAPPING)
            {
                /* If we were swapping the object out, cancel the operation */
                if (val->storage == REDIS_VM_SWAPPING)
                    vmCancelThreadedIOJob(val);
            } else {
                int notify = (val->storage == REDIS_VM_LOADING);

                /* Our value was swapped on disk. Bring it at home. */
                redisAssert(val->type == REDIS_VMPOINTER);
                val = vmLoadObject(val);
                dictGetEntryVal(de) = val;

                /* Clients blocked by the VM subsystem may be waiting for
                 * this key... */
                if (notify) handleClientsBlockedOnSwappedKey(db,key);
            }
        }
        server.stat_keyspace_hits++;
        return val;
    } else {
        server.stat_keyspace_misses++;
        return NULL;
    }
}

Redis uses its own hash table implementation to store keys and their values in memory. Inside the db object, the field dict is a pointer to the hash value for the current Redis database (remember there can be up to 16 separate databases in a single Redis server instance, indexed by number).

First, Redis calls dictFind with the database's hash table and a pointer to the key's bytestring. dictFind looks up the hash of the key in the table, using a standard algorithm that should be familiar to anyone who's implemented a hash table (check out dict.c starting at line 391 if you're interested, the table is an array with linked lists for colliding hashes).

If the key is found in the table, dictFind returns a pointer to the entry in the table. Otherwise, it returns NULL. Back in lookupKey, if the entry is not null, Redis retrieves the value (i.e., the Redis object our key references) from the hash table via dictGetEntryVal and takes care of a bit of bookkeeping for expiry and VM, if the key was found, and stats in either case (hits and misses). If the entry was NULL, then lookupKey also returns NULL; we'll see how this is handled by Redis for a reply to the client when the key is not found, which is the case for us at this stage.

With the value of lookupKey, we'll go back up the stack to our callers. Back to lookupKeyReadOrReply, we look at line 60:

# t_string.c:60
        if (!o) addReply(c,reply);

Since we got NULL from lookupKey this time, we call addReply. The value of reply here comes from the call in getGenericCommand, and it is shared.nullbulk. This field in the global struct object shared is initialize thusly:

# redis.c:712
shared.nullbulk = createObject(REDIS_STRING,sdsnew("$-1\r\n"));

We can see that it is a Redis string object who's on-the-wire value is $-1\r\n, meaning a length of -1, Redis's way of indicating null to a client, according to the protocol.

addReply builds the reply to the client. It does this by first setting up a write event on the main event loop listener with _installWriteEvent. This makes sure that the reply is written out to the client connection when there are bytes present in the buffer. Next, Redis adds the reply to the client's buffer. If the reply object were an non-string value like an integer, or a list, or a set, Redis would first decode it to a bytestring that can be serialized to, for example, on a socket. Redis string objects are encoded "raw," or as-is. The nullbulk object is technically a string object, so no decoding is necessary in our case. In any case, the reply bytestring is copied to the client's reply buffer with _addReplyToBuffer, which for all intents and purposes completes the execution of our get command on the server.

The client will read the on-the-wire reply of $-1\r\n and know that it is a string reply of length -1, and therefore is the null (or "nil," in the context of redis-cli) object, and to convert that into the appropriate object for the language of the client. Back to our redis-cli client patiently waiting for a reply from our breakpointed server, which we continue from, that looks like:

(nil)
redis>

SET

The set command proceeds much the same way as the get, up to the point of command dispatching on the server.

# client
redis> set users:1234 "Paul Smith"

# server
Breakpoint 1, readQueryFromClient (el=0x100400000, fd=6, privdata=0x100805e00, mask=1) at networking.c:801
801     void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
(gdb) n
802         redisClient *c = (redisClient*) privdata;
(gdb) n
808         nread = read(fd, buf, REDIS_IOBUF_LEN);
(gdb) n
809         if (nread == -1) {
(gdb) print nread
$1 = 47
(gdb) x/47cb buf
0x7fff5fbfeba0: 42 '*'  51 '3'  13 '\r' 10 '\n' 36 '$'  51 '3'  13 '\r' 10 '\n'
0x7fff5fbfeba8: 115 's' 101 'e' 116 't' 13 '\r' 10 '\n' 36 '$'  49 '1'  48 '0'
0x7fff5fbfebb0: 13 '\r' 10 '\n' 117 'u' 115 's' 101 'e' 114 'r' 115 's' 58 ':'
0x7fff5fbfebb8: 49 '1'  50 '2'  51 '3'  52 '4'  13 '\r' 10 '\n' 36 '$'  49 '1'
0x7fff5fbfebc0: 48 '0'  13 '\r' 10 '\n' 80 'P'  97 'a'  117 'u' 108 'l' 32 ' '
0x7fff5fbfebc8: 83 'S'  109 'm' 105 'i' 116 't' 104 'h' 13 '\r' 10 '\n'
(gdb) print (char *)buf
$2 = 0x7fff5fbfeba0 "*3\r\n$3\r\nset\r\n$10\r\nusers:1234\r\n$10\r\nPaul Smith\r\n"

This time, our protocol-encoded bytestring is 47 bytes long, owing to the extra argument "Paul Smith" and the length tag it requires. Also notice the leading *3 indicates there are three arguments: set, users:1234, Paul Smith.

Let's skip ahead now to the point in call in redis.c, after the command has been looked-up in the command table and the server is about ready to call the underlying proc function with the client object argument. The set command, in the form of a redisCommand struct, looks like this:

# redis.c:73
{"set",setCommand,3,REDIS_CMD_DENYOOM,NULL,0,0,0},

Notice that the arity of the command is 3, which includes the leading command name, plus key and value, and matches what we expect from the client. The set command has a flag that get did not: the constant REDIS_CMD_DENYOOM means that, in out-of-memory situations where Redis can't allocate any more memory, the execution of the command should be denied. (The absence of this flag means that Redis can continue to serve client "read" requests like get even when the server can no longer write any new data.)

I set a breakpoint on setCommand and let the server continue running until that point:

# server
(gdb) b setCommand
Breakpoint 2 at 0x10001a6e2: file t_string.c, line 48.
(gdb) c
Continuing.
Breakpoint 2, setCommand (c=0x100805e00) at t_string.c:48
48          c->argv[2] = tryObjectEncoding(c->argv[2]);

Incidentally, you can inspect the values of the client's command arguments at any time, with a simple gdb invocation. The arguments are of type robj, which has a field ptr that is a pointer to the actual value in memory. Since in our set case these are strings, we can inspect them by typecasting to char * like so:

(gdb) p (char *)c->argv[0]->ptr
$10 = 0x10032ae78 "set"
(gdb) p (char *)c->argv[1]->ptr
$11 = 0x10032b068 "users:1234"
(gdb) p (char *)c->argv[2]->ptr
$12 = 0x10032b098 "Paul Smith"

The first thing the server does in setCommand is encode the value being set with tryObjectEncoding. It will try to create an efficient encoding if the bytestring can be interpreted as an integer, for example. This can save space especially in the case where many numbers are being stored. Additionally, Redis will try to reuse shared integers as values instead of allocating resources for new ones -- see the previous article for more on the creation and use of shared integers.

Once the value being set has been encoded, setGenericCommand is called (set shares setGenericCommand with the setnx and setex commands). From here, dbAdd is called, with the client, key, and value as arguments. dbAdd will only add the value to the database's hash table if the key does not already exist. In our case, since the key users:1234 does not exist, the value of dictFind is null, and the function proceeds to add the value with dictAdd.

dictAdd takes the dictionary hash table, key, and value as arguments. It uses _dictKeyIndex to find the index of a free slot in the hash table for our new entry. See the implementation in dict.c and dict.h for the details of key hashing, and the structure of the dictionary and its component hash tables (each Redis dictionary contains two hash tables in order to provide incremental rehashing as the dictionary grows). dictAdd allocates memory for the new entry and stores it in the new index.

The server returns back up the stack from dictAdd and dbAdd to setGenericCommand, where it increments the reference count on our new value. Redis uses reference counting in order to free memory used by values that have been deleted or have expired. It then "touches" the key so that if any clients are watching the key, the next exec command will fail. It also increments the server's dirty flag, which it uses to determine when to write out the dump file to disk. Finally, it writes out the reply to the client, which is a shared object, shared.ok. This is special Redis string object in the protocol that consists of the bytestring "+OK\r\n". Clients will typically convert this into the equivalent "true" value for their language.

GET redux

Our key is now set, so we can try the get users:1234 command again and see how it differs for a found key.

# db.c:9
robj *lookupKey(redisDb *db, robj *key) {
    dictEntry *de = dictFind(db->dict,key->ptr);
    if (de) {
        robj *val = dictGetEntryVal(de);

        // ... skipping the lru & vm parts ... 

        server.stat_keyspace_hits++;
        return val;

The point where a get on an existing key and a get on a non-existent key differ is line 11, where the de entry in the database's dictionary is found. dictGetEntryVal is a simple macro for accessing the field in the de struct that carries the value associated with the key. Redis updates its statistics to indicate a key hit and returns the value object.

Again, as with the key miss from above (remember the null value is a Redis object, too), the value is decoded into the Redis bytestring protocol. This is the response to the client, and we have concluded our GET/SET/GET dance.