>
The index format is simple: one line per record, exactly 58 bytes: :\n.It would be much better to write all of this as binary data, omitting separators.
• Since it’s fixed-width and simple, inspecting the data is still pretty easy—there are tools for working with binary data of declared schema, or you could write a few-liner to convert it yourself. You don’t lose much by departing ASCII.
• You might want to complicate it a little by writing a version tag at the start of the file or outside it so you can change the format more easily (e.g. if you ever add a third column). I will admit the explicit separators do make that easier. You can also leave that for later, it probably won’t hurt.
• UUID: 36 bytes → 16 bytes.
• Offset: 20 bytes (zero-padded base-ten integer) → 8 bytes.
• It removes one type of error altogether: now all bit patterns are syntactically valid.
• It’ll use less disk space, be cheaper to read, be cheaper to write, and probably take less code.
I also want to register alarm at the sample code given for func FindUserBinarySearch. To begin with, despite a return type of (*User, error), it always returns nil error—it swallows all I/O errors and ignores JSON decode errors. Then:
entryID := strings.TrimRight(string(buf[:36]), " ")
That strings.TrimRight will only do anything if your data is corrupted.
cmp := strings.Compare(entryID, id)
Not important when you control the writing, but worth noting that UUID string comparison is case-insensitive.
offsetStr := strings.TrimLeft(string(buf[37:57]), "0")
Superfluous. ParseInt doesn’t mind leading zeroes, and it’ll probably skip them faster than a separate TrimLeft call.
dataOffset, _ := strconv.ParseInt(offsetStr, 10, 64)
That’s
begging to make data corruption difficult to debug. Most corruption will now become dataOffset 0. Congratulations! You are now root.