Vesper Sync Diary #13: Unlucky Numbers
I’ve been writing Cocoa apps for so long that I’m rarely surprised. I don’t know everything — surprises happen, and of course there are things that I know I don’t know — but, in the main, I know the intricacies well enough that I don’t even have to think about them.
If you have Node.js installed on your system, you can open Terminal and do this.
Launch Node. (Just type
node and hit return.)
Copy-and-paste the following number and hit return:
Node evaluates the expression. What do you think you get?
That’s right. It’s not the same number.
I had no idea.
I should have known. Well, it’s a thing I needed to learn, and I just learned it.
When does a note-taking app need to deal with very large numbers? After all, if someone types a big number into a note, it doesn’t matter, because the entire note is treated as a string.
Here’s the thing: unique IDs for notes and users are 64-bit integers in my system.
So when the iOS app sends a note to the server, it sends a 64-bit integer along with note text and other properties of the note.
I’m writing this up as soon as I learned about it. I have to figure out what to do.
Before we get anywhere near 2147483647 (max for 32-bit integers), we will have hired a team of the brightest server-side programmers in the world, and they’ll figure out what to do.
But that still leaves note IDs.
Option 1: stringify
Problem: database bloat. Storing strings takes up way more space than storing 64-bit integers.
Plus it’s inelegant.
Option 2: 32-bit integers
Collisions are more likely on assigning a random note ID when using 32-bit integers instead of 64-bit integers.
Now, the client app does check for collisions by looking at the note IDs it knows about.
But there may be a few note IDs it doesn’t know about (that haven’t been synced from another client, for instance).
That’s a very, very small risk. Most of the time there won’t be unknown note IDs, and when there are it will tend to be very few.
But still: ugh.
(Remember that global note ID collisions aren’t an issue. A given note ID has to be unique for a given user only.)
Option 3: 53-bit integers
> Math.pow(2, 53)
The downside is still that there’s a chance of collisions — but, really, that’s a sufficiently large number size that I’m not at all concerned. (Remember that the client app checks, so the chance of a collision is really with a new note ID and any note IDs the client doesn’t know about yet, which will usually be zero anyway.)
And — it just occurred to me that I can add a second collision check: if a note comes from the server that matches the unique ID of an existing note, and the creation dates of the notes are not identical, then I can deal with that. (By giving one of the two notes a new ID and syncing.)
This is what I’ll do.