Exemple #1
0
        public static Slice EncodeKey <T1, T2>(this ICompositeKeyEncoder <T1, T2> encoder, Slice prefix, T1 item1, T2 item2)
        {
            var writer = new SliceWriter(prefix.Count + 24);

            writer.WriteBytes(in prefix);
            encoder.WriteKeyTo(ref writer, item1, item2);
            return(writer.ToSlice());
        }
Exemple #2
0
        public static Slice EncodeKey <T1>([NotNull] this IKeyEncoder <T1> encoder, Slice prefix, T1 value)
        {
            var writer = new SliceWriter(prefix.Count + 16);             // ~16 bytes si T1 = Guid

            writer.WriteBytes(in prefix);
            encoder.WriteKeyTo(ref writer, value);
            return(writer.ToSlice());
        }
Exemple #3
0
        /// <summary>Pack a tuple into a key, using the specified encoder</summary>
        public static Slice Pack <TTuple>(this IDynamicKeyEncoder encoder, TTuple tuple)
            where TTuple : IVarTuple
        {
            var writer = new SliceWriter(checked (tuple.Count * 8));

            encoder.PackKey(ref writer, tuple);
            return(writer.ToSlice());
        }
Exemple #4
0
        public static Slice EncodePartialKey <T1, T2>(this ICompositeKeyEncoder <T1, T2> encoder, Slice prefix, T1 item1)
        {
            var writer = new SliceWriter(prefix.Count + 16);

            writer.WriteBytes(in prefix);
            var tuple = (item1, default(T2));

            encoder.WriteKeyPartsTo(ref writer, 1, ref tuple);
            return(writer.ToSlice());
        }
Exemple #5
0
        public void Test_WriteBytes_Resize_Buffer()
        {
            // check buffer resize occurs as intended
            var original = new byte[32];
            var writer   = new SliceWriter(original);

            Assert.That(writer.Buffer, Is.SameAs(original));

            // first write should not resize the buffer
            writer.WriteBytes(Slice.Repeat((byte)'a', 24));
            Assert.That(writer.Buffer, Is.SameAs(original));
            Assert.That(writer.ToSlice().ToStringAscii(), Is.EqualTo("aaaaaaaaaaaaaaaaaaaaaaaa"));

            // second write should resize the buffer
            writer.WriteBytes(Slice.Repeat((byte)'b', 24));
            // buffer should have been replaced with larger one
            Assert.That(writer.Buffer, Is.Not.SameAs(original));
            Assert.That(writer.Buffer.Length, Is.GreaterThanOrEqualTo(48));

            //but the content should be unchanged
            Assert.That(writer.ToSlice().ToStringAscii(), Is.EqualTo("aaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbb"));

            // adding exactly what is missing should not resize the buffer
            writer = new SliceWriter(original);
            writer.WriteBytes(Slice.Repeat((byte)'c', original.Length));
            Assert.That(writer.Buffer, Is.SameAs(original));
            Assert.That(writer.ToSlice().ToStringAscii(), Is.EqualTo("cccccccccccccccccccccccccccccccc"));

            // adding nothing should not resize the buffer
            writer.WriteBytes(Slice.Empty);
            Assert.That(writer.Buffer, Is.SameAs(original));
            Assert.That(writer.ToSlice().ToStringAscii(), Is.EqualTo("cccccccccccccccccccccccccccccccc"));

            // adding a single byte should resize the buffer
            writer.WriteBytes(Slice.FromChar('Z'));
            Assert.That(writer.Buffer, Is.Not.SameAs(original));
            Assert.That(writer.Buffer.Length, Is.GreaterThanOrEqualTo(33));
            Assert.That(writer.ToSlice().ToStringAscii(), Is.EqualTo("ccccccccccccccccccccccccccccccccZ"));
        }
Exemple #6
0
        public void Test_Skip()
        {
            var writer = new SliceWriter();

            writer.WriteBytes(Slice.FromString("hello"));
            Assert.That(writer.Position, Is.EqualTo(5));
            Assert.That(writer.ToSlice().ToString(), Is.EqualTo("hello"));

            // default pad is 255
            Assert.That(writer.Skip(3), Is.EqualTo(5));
            Assert.That(writer.Position, Is.EqualTo(8));
            Assert.That(writer.ToSlice().ToString(), Is.EqualTo("hello<FF><FF><FF>"));

            writer.WriteBytes(Slice.FromString("world"));
            Assert.That(writer.Position, Is.EqualTo(13));
            Assert.That(writer.ToSlice().ToString(), Is.EqualTo("hello<FF><FF><FF>world"));

            // custom pad
            Assert.That(writer.Skip(5, 42), Is.EqualTo(13));
            Assert.That(writer.Position, Is.EqualTo(18));
            Assert.That(writer.ToSlice().ToString(), Is.EqualTo("hello<FF><FF><FF>world*****"));
        }
Exemple #7
0
        public void Test_ToSlice()
        {
            var writer = new SliceWriter(64);
            var slice  = writer.ToSlice();

            //note: slice.Array is not guaranteed to be equal to writer.Buffer
            Assert.That(slice.Count, Is.EqualTo(0));
            Assert.That(slice.Offset, Is.EqualTo(0));

            writer.WriteBytes(Slice.FromString("hello world!"));
            slice = writer.ToSlice();
            Assert.That(slice.Array, Is.SameAs(writer.Buffer));
            Assert.That(slice.Offset, Is.EqualTo(0));
            Assert.That(slice.Count, Is.EqualTo(12));
            Assert.That(slice.ToStringAscii(), Is.EqualTo("hello world!"));

            writer.WriteBytes(Slice.FromString("foo"));
            slice = writer.ToSlice();
            Assert.That(slice.Array, Is.SameAs(writer.Buffer));
            Assert.That(slice.Offset, Is.EqualTo(0));
            Assert.That(slice.Count, Is.EqualTo(15));
            Assert.That(slice.ToStringAscii(), Is.EqualTo("hello world!foo"));
        }
Exemple #8
0
        public void Test_Flush()
        {
            var writer = new SliceWriter();

            writer.WriteBytes(Slice.FromString("hello world!"));
            Assert.That(writer.Position, Is.EqualTo(12));

            writer.Flush(5);
            Assert.That(writer.Position, Is.EqualTo(7));
            Assert.That(writer.ToSlice().ToString(), Is.EqualTo(" world!"));

            writer.Flush(1);
            Assert.That(writer.Position, Is.EqualTo(6));
            Assert.That(writer.ToSlice().ToString(), Is.EqualTo("world!"));

            writer.Flush(0);
            Assert.That(writer.Position, Is.EqualTo(6));
            Assert.That(writer.ToSlice().ToString(), Is.EqualTo("world!"));

            // REVIEW: should we throw if we flush more bytes than in the writer? (currently, it just clears it)
            writer.Flush(7);
            Assert.That(writer.Position, Is.EqualTo(0));
            Assert.That(writer.ToSlice(), Is.EqualTo(Slice.Empty));
        }
Exemple #9
0
        public void Test_AppendBytes()
        {
            var writer = new SliceWriter(64);
            var slice  = writer.AppendBytes(Slice.Empty);

            //note: slice.Array is not guaranteed to be equal to writer.Buffer
            Assert.That(slice.Offset, Is.EqualTo(0));
            Assert.That(slice.Count, Is.EqualTo(0));

            slice = writer.AppendBytes(Slice.FromString("hello world!"));
            Assert.That(slice.Array, Is.SameAs(writer.Buffer));
            Assert.That(slice.Offset, Is.EqualTo(0));
            Assert.That(slice.Count, Is.EqualTo(12));
            Assert.That(slice.ToStringUtf8(), Is.EqualTo("hello world!"));
            Assert.That(writer.ToSlice().ToStringUtf8(), Is.EqualTo("hello world!"));

            var foo = Slice.FromString("foo");

            slice = writer.AppendBytes(foo);
            Assert.That(slice.Array, Is.SameAs(writer.Buffer));
            Assert.That(slice.Offset, Is.EqualTo(12));
            Assert.That(slice.Count, Is.EqualTo(3));
            Assert.That(slice.ToStringUtf8(), Is.EqualTo("foo"));
            Assert.That(writer.ToSlice().ToStringUtf8(), Is.EqualTo("hello world!foo"));

            var bar = Slice.FromString("bar");

            unsafe
            {
                fixed(byte *ptr = &bar.DangerousGetPinnableReference())
                {
                    slice = writer.AppendBytes(ptr, 3);
                }
            }
            Assert.That(slice.Array, Is.SameAs(writer.Buffer));
            Assert.That(slice.Offset, Is.EqualTo(15));
            Assert.That(slice.Count, Is.EqualTo(3));
            Assert.That(slice.ToStringUtf8(), Is.EqualTo("bar"));
            Assert.That(writer.ToSlice().ToStringUtf8(), Is.EqualTo("hello world!foobar"));

            var baz = Slice.FromString("baz");

            unsafe
            {
                fixed(byte *ptr = &baz.DangerousGetPinnableReference())
                {
                    //TODO: this test was using ReadOnlySpan<byte>, update it once we enable support for these!
                    slice = writer.AppendBytes(ptr, 3);
                }
            }
            Assert.That(slice.Array, Is.SameAs(writer.Buffer));
            Assert.That(slice.Offset, Is.EqualTo(18));
            Assert.That(slice.Count, Is.EqualTo(3));
            Assert.That(slice.ToStringUtf8(), Is.EqualTo("baz"));
            Assert.That(writer.ToSlice().ToStringUtf8(), Is.EqualTo("hello world!foobarbaz"));

            unsafe
            {
                slice = writer.AppendBytes(null, 0);
            }
            //note: slice.Array is not guaranteed to be equal to writer.Buffer
            Assert.That(slice.Offset, Is.EqualTo(0));             //REVIEW: should we return (Buffer, Position, 0) instead of (EmptyArray, 0, 0) ?
            Assert.That(slice.Count, Is.EqualTo(0));
        }
        /// <summary>Write the header to the file</summary>
        /// <param name="headerFlags"></param>
        /// <param name="uid"></param>
        /// <param name="sequence"></param>
        /// <param name="count"></param>
        /// <param name="timestamp"></param>
        /// <param name="attributes"></param>
        /// <remarks>This needs to be called before writing any level to the file</remarks>
        public Task WriteHeaderAsync(SnapshotFormat.Flags headerFlags, Uuid128 uid, ulong sequence, long count, long timestamp, IDictionary <string, IFdbTuple> attributes)
        {
            // The header will be use on ore more "pages", to simplify the job of loading / peeking at a stream content (no need for fancy buffering, just need to read 4K pages)
            // > The last page is padded with 0xAAs to detect corruption.

            m_uid       = uid;
            m_sequence  = sequence;
            m_itemCount = count;
            m_timestamp = timestamp;

            // HEADER
            // - DB_HEADER (64 bytes)
            // - DB ATTRIBUTES (variable size list of k/v)
            // - END_MARKER + HEADER_CRC
            // - PADDING (to fill last page)

            // DB Header

            // "PNDB"
            m_writer.WriteFixed32(SnapshotFormat.HEADER_MAGIC_NUMBER);
            // v1.0
            m_writer.WriteFixed16(1);             // major
            m_writer.WriteFixed16(0);             // minor
            // FLAGS
            m_writer.WriteFixed64((ulong)headerFlags);
            // Database ID
            m_writer.WriteBytes(uid.ToSlice());
            // Database Version
            m_writer.WriteFixed64(sequence);
            // Number of items in the database
            m_writer.WriteFixed64((ulong)count);
            // Database Timestamp
            m_writer.WriteFixed64((ulong)timestamp);
            // Page Size
            m_writer.WriteFixed32(SnapshotFormat.PAGE_SIZE);
            // Header Size (not known yet and will be filled in later)
            int offsetToHeaderSize = m_writer.Skip(4);

            // we should be at the 64 byte mark
            Contract.Assert(m_writer.Position == SnapshotFormat.HEADER_METADATA_BYTES);

            // DB Attributes
            m_writer.WriteFixed32((uint)attributes.Count);
            foreach (var kvp in attributes)
            {
                // Name
                m_writer.WriteVarbytes(Slice.FromString(kvp.Key));

                // Value
                m_writer.WriteVarbytes(kvp.Value.ToSlice());
            }

            // Mark the end of the header
            m_writer.WriteFixed32(uint.MaxValue);

            // we now have the size of the header, and can fill in the blank
            var headerEnd = m_writer.Position;

            m_writer.Position = offsetToHeaderSize;
            // write the header size (includes the CRC)
            m_writer.WriteFixed32((uint)checked (headerEnd + SnapshotFormat.HEADER_CRC_SIZE));
            m_writer.Position = headerEnd;

            // now we can compute the actual CRC
            uint headerChecksum = SnapshotFormat.ComputeChecksum(m_writer.ToSlice());

            m_writer.WriteFixed32(headerChecksum);
            m_headerChecksum = headerChecksum;

            // optional padding to fill the rest of the page
            PadPageIfNeeded(SnapshotFormat.PAGE_SIZE, 0xFD);

            return(TaskHelpers.CompletedTask);
        }