Search code examples
redisbooksleeve

Dealing with Int64 value with Booksleeve


I have a question about Marc Gravell's Booksleeve library.

I tried to understand how booksleeve deal the Int64 value (i have billion long value in Redis actually)

I used reflection to undestand the Set long value overrides.

// BookSleeve.RedisMessage
protected static void WriteUnified(Stream stream, long value)
{
if (value >= 0L && value <= 99L)
{
    int i = (int)value;
    if (i <= 9)
    {
        stream.Write(RedisMessage.oneByteIntegerPrefix, 0, RedisMessage.oneByteIntegerPrefix.Length);
        stream.WriteByte((byte)(48 + i));
    }
    else
    {
        stream.Write(RedisMessage.twoByteIntegerPrefix, 0, RedisMessage.twoByteIntegerPrefix.Length);
        stream.WriteByte((byte)(48 + i / 10));
        stream.WriteByte((byte)(48 + i % 10));
    }
}
else
{
    byte[] bytes = Encoding.ASCII.GetBytes(value.ToString());
    stream.WriteByte(36);
    RedisMessage.WriteRaw(stream, (long)bytes.Length);
    stream.Write(bytes, 0, bytes.Length);
}

stream.Write(RedisMessage.Crlf, 0, 2);
}

I don't understand why, with more than two digits int64, the long is encoding in ascii?

Why don't use byte[] ? I know than i can use byte[] overrides to do this, but i just want to understand this implementation to optimize mine. There may be a relationship with the Redis storage.

By advance thank you Marc :)

P.S : i'm still very enthusiastic about your next major version, than i can use long value key instead of string.


Solution

  • It writes it in ASCII because that is what the redis protocol demands.

    If you look carefully, it is always encoded as ASCII - but for the most common cases (0-9, 10-99) I've special-cased it, as these are very simple results:

     x => $1\r\nX\r\n
    xy => $2\r\nXY\r\n
    

    where x and y are the first two digits of a number in the range 0-99, and X and Y are those digits (as numbers) offset by 48 ('0') - so decimal 17 becomes the byte sequence (in hex):

    24-32-0D-0A-31-37-0D-0A
    

    Of course, that can also be achieved simply via the writing each digit sequentially and offsetting the digit value by 48 ('0'), and handling the negative sign - I guess the answer there is simply "because I coded it the simple but obviously correct way". Consider the value -123 - which is encoded as $4\r\n-123\r\n (hey, don't look at me - I didn't design the protocol). It is slightly awkward because it needs to calculate the buffer length first, then write that buffer length, then write the value - remembering to write in the order 100s, 10s, 1s (which is much harder than writing the other way around).

    Perfectly willing to revisit it - simply: it works.

    Of course, it becomes trivial if you have a scratch buffer available - you just write it in the simple order, then reverse the portion of the scratch buffer. I'll check to see if one is available (and if not, it wouldn't be unreasonable to add one).

    I should also clarify: there is also the integer type, which would encode -123 as :-123\r\n - however, from memory there are a lot of places this simply does not work.