public override unsafe void Write(Slice changeVector, Stream stream, byte[] tempBuffer, OutgoingReplicationStatsScope stats)
        {
            fixed(byte *pTemp = tempBuffer)
            {
                if (AssertChangeVectorSize() > tempBuffer.Length)
                {
                    ThrowTooManyChangeVectorEntries(this, Key.ToString());
                }

                var tempBufferPos = WriteCommon(changeVector, pTemp);

                *(int *)(pTemp + tempBufferPos) = Key.Size;
                tempBufferPos += sizeof(int);
                Memory.Copy(pTemp + tempBufferPos, Key.Content.Ptr, Key.Size);
                tempBufferPos += Key.Size;

                *(int *)(pTemp + tempBufferPos) = Name.Size;
                tempBufferPos += sizeof(int);
                Memory.Copy(pTemp + tempBufferPos, Name.Buffer, Name.Size);
                tempBufferPos += Name.Size;

                *(int *)(pTemp + tempBufferPos) = ContentType.Size;
                tempBufferPos += sizeof(int);
                Memory.Copy(pTemp + tempBufferPos, ContentType.Buffer, ContentType.Size);
                tempBufferPos += ContentType.Size;

                pTemp[tempBufferPos++] = (byte)Base64Hash.Size;
                Base64Hash.CopyTo(pTemp + tempBufferPos);
                tempBufferPos += Base64Hash.Size;

                stream.Write(tempBuffer, 0, tempBufferPos);
            }
        }
        /// <summary>Creates a new binary buffer, initialized by copying pre-existing data</summary>
        /// <param name="prefix">Data that will be copied at the start of the buffer</param>
        /// <param name="capacity">Optional initial capacity of the buffer</param>
        /// <remarks>The cursor will already be placed at the end of the prefix</remarks>
        public SliceWriter(Slice prefix, int capacity = 0)
        {
            if (capacity < 0)
            {
                throw new ArgumentException("Capacity must be a positive integer.", "capacity");
            }

            int n = prefix.Count;

            Contract.Assert(n >= 0);

            if (capacity == 0)
            {             // most frequent usage is to add a packed integer at the end of a prefix
                capacity = SliceHelpers.Align(n + 8);
            }
            else
            {
                capacity = Math.Max(capacity, n);
            }

            var buffer = new byte[capacity];

            if (n > 0)
            {
                prefix.CopyTo(buffer, 0);
            }

            this.Buffer   = buffer;
            this.Position = n;
        }
Example #3
0
        internal Slice Grab(Slice slice)
        {
            if (slice.IsNullOrEmpty)
            {
                return(slice.IsNull ? Slice.Nil : Slice.Empty);
            }

            lock (m_lock)
            {
                if (slice.Count > m_buffer.Length - m_offset)
                {                 // not enough ?
                    if (slice.Count >= 2048)
                    {
                        return(slice.Memoize());
                    }
                    m_buffer = new byte[4096];
                    m_offset = 0;
                }

                int start = m_offset;
                slice.CopyTo(m_buffer, m_offset);
                m_offset += slice.Count;
                return(m_buffer.AsSlice(start, slice.Count));
            }
        }
        private void AssertSliceDataEqual(byte[] expected, Slice actual)
        {
            var actualSliceData = new byte[actual.Length];

            actual.CopyTo(new ArraySegment <byte>(actualSliceData));
            CollectionAssert.AreEqual(expected, actualSliceData);
        }
Example #5
0
        /// <summary>
        /// Internal method that is used when splitting pages
        /// No need to do any work here, we are always adding at the end
        /// </summary>
        internal void CopyNodeDataToEndOfPage(TreeNodeHeader *other, Slice key)
        {
            var index = NumberOfEntries;

            Debug.Assert(HasSpaceFor(TreeSizeOf.NodeEntryWithAnotherKey(other, key) + Constants.Tree.NodeOffsetSize));

            var nodeSize = TreeSizeOf.NodeEntryWithAnotherKey(other, key);

            Debug.Assert(IsBranch == false || index != 0 || key.Size == 0);// branch page's first item must be the implicit ref

            var newNode = AllocateNewNode(index, nodeSize);

            Debug.Assert(key.Size <= ushort.MaxValue);
            newNode->KeySize = (ushort)key.Size;
            newNode->Flags   = other->Flags;

            if (key.Options == SliceOptions.Key && key.Size > 0)
            {
                key.CopyTo((byte *)newNode + Constants.Tree.NodeHeaderSize);
            }

            if (IsBranch || other->Flags == (TreeNodeFlags.PageRef))
            {
                newNode->PageNumber = other->PageNumber;
                newNode->Flags      = TreeNodeFlags.PageRef;
                return;
            }
            newNode->DataSize = other->DataSize;
            Memory.Copy((byte *)newNode + Constants.Tree.NodeHeaderSize + key.Size,
                        (byte *)other + Constants.Tree.NodeHeaderSize + other->KeySize,
                        other->DataSize);
        }
Example #6
0
        private void WritePrefix(Slice prefix, int prefixId)
        {
            var prefixNodeSize = Constants.PrefixNodeHeaderSize + prefix.Size;

            prefixNodeSize += prefixNodeSize & 1;

            var prefixNodeOffset = (ushort)(Upper - prefixNodeSize);

            Upper = prefixNodeOffset;

            Debug.Assert(_prefixSection->NextPrefixId == prefixId);

            if (_prefixSection->PrefixOffsets[prefixId] != 0)
            {
                throw new InvalidOperationException(string.Format("Cannot write a prefix '{0}' at the following offset position: {1} because it's already taken by another prefix. The offset for the prefix {1} is {2}. ", prefix, prefixId, _prefixSection->PrefixOffsets[prefixId]));
            }

            _prefixSection->PrefixOffsets[prefixId] = prefixNodeOffset;

            var prefixNodeHeader = (PrefixNodeHeader *)(_base + prefixNodeOffset);

            prefixNodeHeader->PrefixLength = prefix.Size;

            prefix.CopyTo((byte *)prefixNodeHeader + Constants.PrefixNodeHeaderSize);

            _prefixSection->NextPrefixId++;
        }
Example #7
0
        private TreeNodeHeader *CreateNode(int index, Slice key, TreeNodeFlags flags, int len)
        {
            Debug.Assert(index <= NumberOfEntries && index >= 0);
            Debug.Assert(IsBranch == false || index != 0 || key.Size == 0);// branch page's first item must be the implicit ref
            if (HasSpaceFor(key, len) == false)
            {
                throw new InvalidOperationException(string.Format("The page is full and cannot add an entry, this is probably a bug. Key: {0}, data length: {1}, size left: {2}", key, len, SizeLeft));
            }

            // move higher pointers up one slot
            ushort *offsets = KeysOffsets;

            for (int i = NumberOfEntries; i > index; i--)
            {
                offsets[i] = offsets[i - 1];
            }

            var nodeSize = TreeSizeOf.NodeEntry(PageMaxSpace, key, len);
            var node     = AllocateNewNode(index, nodeSize);

            node->Flags = flags;

            Debug.Assert(key.Size <= ushort.MaxValue);
            node->KeySize = (ushort)key.Size;
            if (key.Options == SliceOptions.Key && node->KeySize > 0)
            {
                key.CopyTo((byte *)node + Constants.Tree.NodeHeaderSize);
            }

            return(node);
        }
Example #8
0
        private NodeHeader *CreateNode(int index, Slice key, NodeFlags flags, int len, ushort previousNodeVersion)
        {
            Debug.Assert(index <= NumberOfEntries && index >= 0);
            Debug.Assert(IsBranch == false || index != 0 || key.Size == 0);// branch page's first item must be the implicit ref
            if (HasSpaceFor(key, len) == false)
            {
                throw new InvalidOperationException("The page is full and cannot add an entry, this is probably a bug");
            }

            // move higher pointers up one slot
            for (int i = NumberOfEntries; i > index; i--)
            {
                KeysOffsets[i] = KeysOffsets[i - 1];
            }
            var nodeSize = SizeOf.NodeEntry(PageMaxSpace, key, len);
            var node     = AllocateNewNode(index, key, nodeSize, previousNodeVersion);

            if (key.Options == SliceOptions.Key)
            {
                key.CopyTo((byte *)node + Constants.NodeHeaderSize);
            }

            node->Flags = flags;

            return(node);
        }
Example #9
0
            public void IncreaseSize(int additionalCapacity)
            {
                if (additionalCapacity <= 0)
                {
                    return;
                }

                // Creating a new reservation may overwrite the particles this slice is using, so we have to
                // make a temporary copy of all of our current particles.
                var temp = new Particle[Slice.Length];

                Slice.CopyTo(temp);

                _pool._allocations.Remove(this);

                // This is ugly but I'm not in the mood to refactor the reservation logic atm
                var newAllocation = _pool.Reserve(temp.Length + additionalCapacity);

                _pool._allocations.Remove(newAllocation);
                StartIndex    = newAllocation.StartIndex;
                LastUsedIndex = newAllocation.LastUsedIndex;
                Slice         = newAllocation.Slice;
                temp.CopyTo(Slice);

                _pool._allocations.Add(this);
            }
Example #10
0
        /// <summary>
        /// Internal method that is used when splitting pages
        /// No need to do any work here, we are always adding at the end
        /// </summary>
        internal void CopyNodeDataToEndOfPage(NodeHeader* other, Slice key = null)
        {
            Debug.Assert(SizeOf.NodeEntry(other) + Constants.NodeOffsetSize <= SizeLeft);
            
            var index = NumberOfEntries;

            var nodeSize = SizeOf.NodeEntry(other);

            key = key ?? new Slice(other);

            Debug.Assert(IsBranch == false || index != 0 || key.Size == 0);// branch page's first item must be the implicit ref


            var newNode = AllocateNewNode(index, key, nodeSize);
            newNode->Flags = other->Flags;
            key.CopyTo((byte*)newNode + Constants.NodeHeaderSize);

            if (IsBranch || other->Flags==(NodeFlags.PageRef))
            {
                newNode->PageNumber = other->PageNumber;
                newNode->Flags = NodeFlags.PageRef;
                return;
            }
            newNode->DataSize = other->DataSize;
            NativeMethods.memcpy((byte*)newNode + Constants.NodeHeaderSize + other->KeySize,
                                 (byte*)other + Constants.NodeHeaderSize + other->KeySize,
                                 other->DataSize);
        }
Example #11
0
        public byte* AddNode(int index, Slice key, int len, long pageNumber)
        {
            Debug.Assert(index <= NumberOfEntries && index >= 0);
            Debug.Assert(IsBranch == false || index != 0 || key.Size == 0);// branch page's first item must be the implicit ref
            if (HasSpaceFor(key, len) == false)
                throw new InvalidOperationException("The page is full and cannot add an entry, this is probably a bug");

            // move higher pointers up one slot
            for (int i = NumberOfEntries; i > index; i--)
            {
                KeysOffsets[i] = KeysOffsets[i - 1];
            }
            var nodeSize = SizeOf.NodeEntry(_pageMaxSpace, key, len);
            var node = AllocateNewNode(index, key, nodeSize);

            if (key.Options == SliceOptions.Key)
                key.CopyTo((byte*)node + Constants.NodeHeaderSize);

			if (len < 0) // branch or overflow
            {
                Debug.Assert(pageNumber != -1);
                node->PageNumber = pageNumber;
	            node->Flags = NodeFlags.PageRef;
                return null; // write nothing here
            }

            Debug.Assert(key.Options == SliceOptions.Key);
            var dataPos = (byte*)node + Constants.NodeHeaderSize + key.Size;
            node->DataSize = len;
	        node->Flags = NodeFlags.Data;
            return dataPos;
        }
Example #12
0
        private static ByteStringContext.ExternalScope CreateCounterKeySlice(DocumentsOperationContext context, ByteString buffer, Slice documentIdPrefix, Slice counterName, out Slice counterKeySlice)
        {
            var scope = Slice.External(context.Allocator, buffer.Ptr, buffer.Length, out counterKeySlice);

            documentIdPrefix.CopyTo(buffer.Ptr);
            counterName.CopyTo(buffer.Ptr + documentIdPrefix.Size);
            return(scope);
        }
Example #13
0
        public void Add(Slice key, Slice value)
        {
            if (!value.HasValue)
            {
                ThrowNullReferenceException();
            }

            using (DirectAdd(key, value.Size, out byte *ptr))
                value.CopyTo(ptr);
        }
Example #14
0
        public void TestCopyToCopiesAllSliceElementsToCorrectLocationInDestination()
        {
            var list     = new[] { 0, 1, 2, 3, 4 };
            var slice    = new Slice <int>(list, 2, 2);
            var expected = new[] { 0, 2, 3 };
            var actual   = new int[3];

            slice.CopyTo(actual, 1);
            CollectionAssert.AreEqual(expected, actual);
        }
Example #15
0
        public void MultiAdd(Transaction tx, Slice key, Slice value, ushort?version = null)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }
            if (value.Size > tx.DataPager.MaxNodeSize)
            {
                throw new ArgumentException(
                          "Cannot add a value to child tree that is over " + tx.DataPager.MaxNodeSize + " bytes in size", "value");
            }
            if (value.Size == 0)
            {
                throw new ArgumentException("Cannot add empty value to child tree");
            }

            State.IsModified = true;
            Lazy <Cursor> lazy;
            var           page = FindPageFor(tx, key, out lazy);

            if (page == null || page.LastMatch != 0)
            {
                var ptr = DirectAdd(tx, key, value.Size, version: version);
                value.CopyTo(ptr);
                return;
            }

            page = tx.ModifyPage(page.PageNumber, page);

            var item = page.GetNode(page.LastSearchPosition);

            CheckConcurrency(key, version, item->Version, TreeActionType.Add);
            var existingValue = new Slice(DirectRead(tx, key), (ushort)item->DataSize);

            if (existingValue.Compare(value, _cmp) == 0)
            {
                return;                 //nothing to do, the exact value is already there
            }
            if (item->Flags == NodeFlags.MultiValuePageRef)
            {
                var tree = OpenOrCreateMultiValueTree(tx, key, item);
                tree.DirectAdd(tx, value, 0);
            }
            else             // need to turn to tree
            {
                var tree    = Create(tx, _cmp, TreeFlags.MultiValue);
                var current = NodeHeader.GetData(tx, item);
                tree.DirectAdd(tx, current, 0);
                tree.DirectAdd(tx, value, 0);
                tx.AddMultiValueTree(this, key, tree);

                // we need to record that we switched to tree mode here, so the next call wouldn't also try to create the tree again
                DirectAdd(tx, key, sizeof(TreeRootHeader), NodeFlags.MultiValuePageRef);
            }
        }
Example #16
0
        public void MultiAdd(Transaction tx, Slice key, Slice value)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }
            if (value.Size > tx.Pager.MaxNodeSize)
            {
                throw new ArgumentException("Cannot add a value to child tree that is over " + tx.Pager.MaxNodeSize + " bytes in size", "value");
            }
            if (value.Size == 0)
            {
                throw new ArgumentException("Cannot add empty value to child tree");
            }

            using (var cursor = tx.NewCursor(this))
            {
                var page = FindPageFor(tx, key, cursor);

                if (page == null || page.LastMatch != 0)
                {
                    var ptr = DirectAdd(tx, key, value.Size);
                    value.CopyTo(ptr);
                    return;
                }

                var txInfo = tx.GetTreeInformation(this);

                page = tx.ModifyCursor(txInfo, cursor);

                var item = page.GetNode(page.LastSearchPosition);

                if (item->Flags == NodeFlags.MultiValuePageRef)
                {
                    var tree = OpenOrCreateMultiValueTree(tx, key, item);
                    tree.DirectAdd(tx, value, 0);
                }
                else // need to turn to tree
                {
                    var tree    = Create(tx, _cmp, TreeFlags.MultiValue);
                    var current = NodeHeader.GetData(tx, item);
                    tree.DirectAdd(tx, current, 0);
                    tree.DirectAdd(tx, value, 0);
                    tx.AddMultiValueTree(this, key, tree);

                    DirectAdd(tx, key, sizeof(TreeRootHeader));

                    cursor.Clear();
                    page = FindPageFor(tx, key, cursor);
                    Debug.Assert(page.LastMatch == 0);
                    page.GetNode(page.LastSearchPosition)->Flags = NodeFlags.MultiValuePageRef;
                }
            }
        }
Example #17
0
        public void Add(Slice key, Slice value)
        {
            if (!value.HasValue)
            {
                throw new ArgumentNullException(nameof(value));
            }

            State.IsModified = true;
            var pos = DirectAdd(key, value.Size);

            value.CopyTo(pos);
        }
Example #18
0
        public void Add(Slice key, Slice value, ushort?version = null)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }

            State.IsModified = true;
            var pos = DirectAdd(key, value.Size, version: version);

            value.CopyTo(pos);
        }
Example #19
0
        private static ByteStringContext <ByteStringMemoryCache> .ExternalScope CreateTimeSeriesKeyPrefixSlice(DocumentsOperationContext context, ByteString buffer,
                                                                                                               Slice documentIdPrefix, Slice timeSeriesName, out Slice timeSeriesPrefixSlice)
        {
            documentIdPrefix.CopyTo(buffer.Ptr);
            timeSeriesName.CopyTo(buffer.Ptr + documentIdPrefix.Size);
            int pos = documentIdPrefix.Size + timeSeriesName.Size;

            buffer.Ptr[pos++] = SpecialChars.RecordSeparator;
            var scope = Slice.External(context.Allocator, buffer.Ptr, pos, out timeSeriesPrefixSlice);

            return(scope);
        }
Example #20
0
        /// <summary>
        /// Transform into the flat variant
        /// </summary>
        private void Flatten()
        {
            if (_variant == Variant.Flat)
            {
                return;
            }

            _chars   = new char[_left.Length + _right.Length + 64];
            _variant = Variant.Flat;

            _left.CopyTo(_chars.Span);
            _right.CopyTo(_chars.Span[_left.Length..]);
Example #21
0
            internal static byte[] PrepareValueForAtomicOperation(Slice value, int size)
            {
                if (value.Count >= size)
                {                 // truncate if needed
                    return(value.GetBytes(0, size));
                }

                // pad with zeroes
                var tmp = new byte[size];

                value.CopyTo(tmp, 0);
                return(tmp);
            }
Example #22
0
        public void SliceFromNativePtr_CopyToArraySegmentTooSmall()
        {
            var origBuffer = GetTestBuffer(100);
            var gcHandle   = GCHandle.Alloc(origBuffer, GCHandleType.Pinned);

            try
            {
                var slice    = new Slice(gcHandle.AddrOfPinnedObject(), origBuffer.Length);
                var tooSmall = new byte[origBuffer.Length - 1];
                Assert.Catch(typeof(ArgumentException), () => slice.CopyTo(new ArraySegment <byte>(tooSmall)));
            }
            finally
            {
                gcHandle.Free();
            }
        }
Example #23
0
        /// <summary>Copy a slice into the buffer, with optional alignment, and return a new identical slice.</summary>
        /// <param name="data">Data to copy in the buffer</param>
        /// <param name="aligned">If true, align the index of first byte of the slice with a multiple of 8 bytes</param>
        /// <returns>Slice that is the equivalent of <paramref name="data"/>, backed by the buffer.</returns>
        public Slice Intern(Slice data, bool aligned = false)
        {
            if (data.Count == 0)
            {
                // transform into the corresponding Slice.Nil / Slice.Empty singleton
                return(data.Memoize());
            }

            data.EnsureSliceIsValid();

            // allocate the slice
            var slice = Allocate(data.Count, aligned);

            data.CopyTo(slice.Span);
            return(slice);
        }
Example #24
0
        /// <summary>Copy a slice into the buffer, immediately followed by a suffix, and return a new slice that is the concatenation of the two.</summary>
        /// <param name="data">Data to copy in the buffer</param>
        /// <param name="suffix">Suffix to copy immediately after <paramref name="data"/>.</param>
        /// <param name="aligned">If true, align the index of first byte of the slice with a multiple of 8 bytes</param>
        /// <returns>Slice that is the equivalent of <paramref name="data"/> plus <paramref name="suffix"/>, backed by the buffer.</returns>
        /// <remarks>When <paramref name="data"/> is empty, <paramref name="suffix"/> is returned without being copied to the buffer itself.</remarks>
        internal Slice Intern(Slice data, Slice suffix, bool aligned = false)
        {
            if (data.Count == 0)
            {
                // note: we don't memoize the suffix, because in most case, it comes from a constant, and it would be a waste to copy it other and other again...
                return(suffix.Count > 0 ? suffix : data.Array == null ? default : Slice.Empty);
            }

            data.EnsureSliceIsValid();
            suffix.EnsureSliceIsValid();

            var slice = Allocate(data.Count + suffix.Count, aligned);

            data.CopyTo(slice.Span);
            suffix.CopyTo(slice.Span.Slice(data.Count));
            return(slice);
        }
Example #25
0
        public void SliceFromNativePtr_CopyToArraySegment(int bufferLength)
        {
            var origBuffer = GetTestBuffer(bufferLength);
            var gcHandle   = GCHandle.Alloc(origBuffer, GCHandleType.Pinned);

            try
            {
                var slice = new Slice(gcHandle.AddrOfPinnedObject(), origBuffer.Length);
                Assert.AreEqual(bufferLength, slice.Length);

                var newBuffer = new byte[bufferLength];
                slice.CopyTo(new ArraySegment <byte>(newBuffer));
                CollectionAssert.AreEqual(origBuffer, newBuffer);
            }
            finally
            {
                gcHandle.Free();
            }
        }
Example #26
0
        public void Delete(DocumentsOperationContext context, CollectionName collectionName, Slice loweredKey)
        {
            var configuration = GetVersioningConfiguration(collectionName);

            if (configuration.Active == false)
            {
                return;
            }

            if (configuration.PurgeOnDelete == false)
            {
                return;
            }

            var table        = context.Transaction.InnerTransaction.OpenTable(DocsSchema, RevisionDocuments);
            var prefixKeyMem = context.Allocator.Allocate(loweredKey.Size + 1);

            loweredKey.CopyTo(0, prefixKeyMem.Ptr, 0, loweredKey.Size);
            prefixKeyMem.Ptr[loweredKey.Size] = (byte)30; // the record separator
            var prefixSlice = new Slice(SliceOptions.Key, prefixKeyMem);

            table.DeleteForwardFrom(DocsSchema.Indexes[KeyAndEtagSlice], prefixSlice, long.MaxValue);
            DeleteCountOfRevisions(context, prefixSlice);
        }
Example #27
0
        public void TestSlice()
        {
            BufferAllocator<float> bufferAllocator = new BufferAllocator<float>(FloatNumSlices * 2048, 1, sizeof(float));
            Buf<float> buffer = bufferAllocator.Allocate();
            Slice<Sample, float> slice = new Slice<Sample, float>(buffer, 0, FloatNumSlices, FloatSliverSize);
            HoloDebug.Assert(slice.Duration == FloatNumSlices);
            HoloDebug.Assert(slice.IsEmpty() == false);
            HoloDebug.Assert(slice.SliverSize == FloatSliverSize);
            var halfDuration = (FloatNumSlices / 2);
            Slice<Sample, float> prefixSlice = slice.Subslice(0, halfDuration);
            Slice<Sample, float> prefixSlice2 = slice.SubsliceOfDuration(halfDuration);
            Slice<Sample, float> suffixSlice = slice.Subslice(halfDuration, halfDuration);
            Slice<Sample, float> suffixSlice2 = slice.SubsliceStartingAt(halfDuration);
            HoloDebug.Assert(prefixSlice.Precedes(suffixSlice));
            HoloDebug.Assert(prefixSlice.Precedes(suffixSlice2));
            HoloDebug.Assert(prefixSlice2.Precedes(suffixSlice));
            HoloDebug.Assert(prefixSlice2.Precedes(suffixSlice2));

            PopulateFloatSlice(slice);

            Buf<float> buffer2 = bufferAllocator.Allocate();
            Slice<Sample, float> slice2 = new Slice<Sample, float>(buffer2, 0, FloatNumSlices, FloatSliverSize);

            slice.CopyTo(slice2);

            VerifySlice(slice2);
        }
Example #28
0
		public void MultiAdd(Transaction tx, Slice key, Slice value, ushort? version = null)
		{
			if (value == null) throw new ArgumentNullException("value");
			if (value.Size > tx.DataPager.MaxNodeSize)
				throw new ArgumentException(
					"Cannot add a value to child tree that is over " + tx.DataPager.MaxNodeSize + " bytes in size", "value");
			if (value.Size == 0)
				throw new ArgumentException("Cannot add empty value to child tree");

			State.IsModified = true;
			Lazy<Cursor> lazy;
			var page = FindPageFor(tx, key, out lazy);

			if (page == null || page.LastMatch != 0)
			{
				var ptr = DirectAdd(tx, key, value.Size, version: version);
				value.CopyTo(ptr);
				return;
			}

			page = tx.ModifyPage(page.PageNumber, page);

			var item = page.GetNode(page.LastSearchPosition);

			CheckConcurrency(key, version, item->Version, TreeActionType.Add);
			var existingValue = new Slice(DirectRead(tx, key), (ushort) item->DataSize);
			if (existingValue.Compare(value, _cmp) == 0)
				return; //nothing to do, the exact value is already there				

			if (item->Flags == NodeFlags.MultiValuePageRef)
			{
				var tree = OpenOrCreateMultiValueTree(tx, key, item);
				tree.DirectAdd(tx, value, 0);
			}
			else // need to turn to tree
			{
				var tree = Create(tx, _cmp, TreeFlags.MultiValue);
				var current = NodeHeader.GetData(tx, item);
				tree.DirectAdd(tx, current, 0);
				tree.DirectAdd(tx, value, 0);
				tx.AddMultiValueTree(this, key, tree);

				// we need to record that we switched to tree mode here, so the next call wouldn't also try to create the tree again
				DirectAdd(tx, key, sizeof (TreeRootHeader), NodeFlags.MultiValuePageRef);
			}
		}
Example #29
0
        public void WritePrefix(Slice prefix, int prefixId)
        {
            var prefixNodeSize = Constants.PrefixNodeHeaderSize + prefix.Size;
            prefixNodeSize += prefixNodeSize & 1;

            var prefixNodeOffset = (ushort)(Upper - prefixNodeSize);
            Upper = prefixNodeOffset;

            Debug.Assert(_prefixSection->NextPrefixId == prefixId);

            if (_prefixSection->PrefixOffsets[prefixId] != 0)
                throw new InvalidOperationException(string.Format("Cannot write a prefix '{0}' at the following offset position: {1} because it's already taken by another prefix. The offset for the prefix {1} is {2}. ", prefix, prefixId, _prefixSection->PrefixOffsets[prefixId]));

            _prefixSection->PrefixOffsets[prefixId] = prefixNodeOffset;

            var prefixNodeHeader = (PrefixNodeHeader*)(_base + prefixNodeOffset);

            prefixNodeHeader->PrefixLength = prefix.Size;

            prefix.CopyTo((byte*)prefixNodeHeader + Constants.PrefixNodeHeaderSize);

            _prefixSection->NextPrefixId++;
        }
Example #30
0
        private NodeHeader* CreateNode(int index, Slice key, NodeFlags flags, int len, ushort previousNodeVersion)
        {
            Debug.Assert(index <= NumberOfEntries && index >= 0);
            Debug.Assert(IsBranch == false || index != 0 || key.Size == 0);// branch page's first item must be the implicit ref
            if (HasSpaceFor(key, len) == false)
                throw new InvalidOperationException("The page is full and cannot add an entry, this is probably a bug");

            // move higher pointers up one slot
            for (int i = NumberOfEntries; i > index; i--)
            {
                KeysOffsets[i] = KeysOffsets[i - 1];
            }
            var nodeSize = SizeOf.NodeEntry(PageMaxSpace, key, len);
            var node = AllocateNewNode(index, key, nodeSize, previousNodeVersion);

            if (key.Options == SliceOptions.Key)
                key.CopyTo((byte*)node + Constants.NodeHeaderSize);

	        node->Flags = flags;

	        return node;
        }
Example #31
0
		/// <summary>Creates a new binary buffer, initialized by copying pre-existing data</summary>
		/// <param name="prefix">Data that will be copied at the start of the buffer</param>
		/// <param name="capacity">Optional initial capacity of the buffer</param>
		/// <remarks>The cursor will already be placed at the end of the prefix</remarks>
		public SliceWriter(Slice prefix, int capacity = 0)
		{
			if (capacity < 0) throw new ArgumentException("Capacity must be a positive integer.", "capacity");

			int n = prefix.Count;
			Contract.Assert(n >= 0);

			if (capacity == 0)
			{ // most frequent usage is to add a packed integer at the end of a prefix
				capacity = SliceHelpers.Align(n + 8);
			}
			else
			{
				capacity = Math.Max(capacity, n);
			}

			var buffer = new byte[capacity];
			if (n > 0) prefix.CopyTo(buffer, 0);

			this.Buffer = buffer;
			this.Position = n;
		}
Example #32
0
		public void Add(Transaction tx, Slice key, Slice value, ushort? version = null)
		{
			if (value == null) throw new ArgumentNullException("value");

			State.IsModified = true;
			var pos = DirectAdd(tx, key, value.Size, version: version);

			value.CopyTo(pos);
		}