예제 #1
0
        public bool ReadKey(BTreeValue *pEntry, ushort keyType, out TangleKey key)
        {
            if (keyType == 0)
            {
                key = default(TangleKey);
                return(false);
            }

            var buffer = ImmutableArrayPool <byte> .Allocate(pEntry->KeyLength);

            if (pEntry->KeyLength <= BTreeValue.KeyPrefixSize)
            {
                fixed(byte *pBuffer = buffer.Array)
                Native.memmove(pBuffer + buffer.Offset, pEntry->KeyPrefix, new UIntPtr(pEntry->KeyLength));
            }
            else
            {
                using (var keyRange = KeyStream.AccessRange(
                           pEntry->KeyOffset, pEntry->KeyLength, MemoryMappedFileAccess.Read
                           ))
                    Unsafe.ReadBytes(keyRange.Pointer, 0, buffer.Array, buffer.Offset, pEntry->KeyLength);
            }

            key = new TangleKey(buffer, keyType);
            return(true);
        }
예제 #2
0
        /// <summary>
        /// Serializes a given value so that it can be written to the provided IndexEntry.
        /// The IndexEntry's KeyLength and KeyOffset values must be filled in and the key must have been written to KeyOffset.
        /// </summary>
        public ArraySegment <byte> Serialize <T> (BTreeValue *pEntry, Serializer <T> serializer, ushort keyType, ref T value)
        {
            if (_SerializationBuffer == null)
            {
                _SerializationBuffer = new MemoryStream();
            }

            var context = new SerializationContext(_GetKeyOfEntry, pEntry, keyType, _SerializationBuffer);

            serializer(ref context, ref value);
            var result = context.Bytes;

            if (_SerializationBuffer.Capacity > MaxSerializationBufferSize)
            {
                _SerializationBuffer.Dispose();
                _SerializationBuffer = null;
            }
            else
            {
                _SerializationBuffer.Seek(0, SeekOrigin.Begin);
                _SerializationBuffer.SetLength(0);
            }

            return(result);
        }
예제 #3
0
 internal DeserializationContext(GetKeyOfEntryFunc getKeyOfEntry, BTreeValue *pEntry, ushort keyType, byte *source, uint sourceLength)
 {
     GetKeyOfEntry = getKeyOfEntry;
     _Key          = default(TangleKey);
     _KeyCached    = false;
     KeyType       = keyType;
     ValuePointer  = pEntry;
     Source        = source;
     SourceLength  = sourceLength;
     _Stream       = null;
 }
예제 #4
0
 public unsafe void ReadData <T> (BTreeValue *pEntry, ushort keyType, Deserializer <T> deserializer, out T value)
 {
     using (var range = DataStream.AccessRange(pEntry->DataOffset, pEntry->DataLength)) {
         var context = new DeserializationContext(_GetKeyOfEntry, pEntry, keyType, range.Pointer, pEntry->DataLength);
         try {
             deserializer(ref context, out value);
         } finally {
             context.Dispose();
         }
     }
 }
예제 #5
0
        public void ReadData <T> (BTreeValue *pEntry, Deserializer <T> deserializer, out T value)
        {
            var keyType = pEntry->KeyType;

            if (keyType == 0)
            {
                throw new InvalidDataException();
            }

            ReadData(pEntry, keyType, deserializer, out value);
        }
예제 #6
0
        public void UnlockValue(BTreeValue *pEntry, ushort keyType)
        {
            unchecked {
                if (pEntry->KeyType != 0)
                {
                    throw new InvalidDataException();
                }

                pEntry->KeyType = keyType;
            }
        }
예제 #7
0
 internal SerializationContext(GetKeyOfEntryFunc getKeyOfEntry, BTreeValue *pEntry, ushort keyType, MemoryStream stream)
 {
     GetKeyOfEntry = getKeyOfEntry;
     ValuePointer  = pEntry;
     KeyType       = keyType;
     _Key          = default(TangleKey);
     _KeyCached    = false;
     _Stream       = stream;
     BytesProvided = false;
     StreamInUse   = false;
     _Bytes        = default(ArraySegment <byte>);
 }
예제 #8
0
        public void WriteData(BTreeValue *pEntry, ArraySegment <byte> data)
        {
            bool append = (data.Count > pEntry->DataLength + pEntry->ExtraDataBytes);

            long?dataOffset;
            uint size = (uint)data.Count;

            if (append)
            {
                dataOffset = AllocateDataSpace(ref size);
            }
            else
            {
                dataOffset = pEntry->DataOffset;
            }

            WriteData(ref *pEntry, data, append, dataOffset, size);
        }
예제 #9
0
        public void WriteNewKey(BTreeValue *pEntry, TangleKey key)
        {
            if (key.Data.Count > BTreeValue.KeyPrefixSize)
            {
                pEntry->KeyOffset = (uint)KeyStream.AllocateSpace((uint)key.Data.Count).Value;
            }
            else
            {
                pEntry->KeyOffset = 0;
            }

            pEntry->KeyLength = (ushort)key.Data.Count;

            // It's important that we zero out these fields so that when we write the data,
            //  it's done in append mode instead of replace mode
            pEntry->DataOffset     = 0;
            pEntry->DataLength     = 0;
            pEntry->ExtraDataBytes = 0;

            WriteKey(ref *pEntry, key);
        }
예제 #10
0
        public bool ReadKey(BTreeValue *pEntry, out TangleKey key)
        {
            ushort keyType = pEntry->KeyType;

            return(ReadKey(pEntry, keyType, out key));
        }
예제 #11
0
        /// <summary>
        /// Performs a binary search of the values stored within a BTree node.
        /// </summary>
        /// <param name="entries">Pointer to the first value within the node.</param>
        /// <param name="entryCount">The number of values within the node.</param>
        /// <param name="pSearchKey">Pointer to the first byte of the key to search for.</param>
        /// <param name="searchKeyLength">The number of bytes in the key to search for.</param>
        /// <param name="resultIndex">The index of the value within the node that matches the provided key, if any, otherwise the index of the leaf that should contain the provided key.</param>
        /// <returns>True if one of the node's values matches the provided key. False if the provided key was not found.</returns>
        private bool SearchValues(BTreeValue *entries, ushort entryCount, byte *pSearchKey, uint searchKeyLength, out uint resultIndex)
        {
            int  min = 0, max = entryCount - 1;
            int  delta = 0, pivot;
            uint compareLength;

            while (min <= max)
            {
                unchecked {
                    pivot = min + ((max - min) >> 1);
                }

                var pEntry = &entries[pivot];
                if (pEntry->KeyType == 0)
                {
                    throw new InvalidDataException();
                }

                compareLength = Math.Min(Math.Min(pEntry->KeyLength, searchKeyLength), BTreeValue.KeyPrefixSize);

                // Calling out to a function here introduces unnecessary overhead since the prefix is so small
                for (uint i = 0; i < compareLength; i++)
                {
                    delta = pEntry->KeyPrefix[i] - pSearchKey[i];
                    if (delta != 0)
                    {
                        break;
                    }
                }

                if ((delta == 0) && (pEntry->KeyLength > BTreeValue.KeyPrefixSize))
                {
                    using (var keyRange = KeyStream.AccessRange(
                               pEntry->KeyOffset, pEntry->KeyLength, MemoryMappedFileAccess.Read
                               )) {
                        var pLhs = keyRange.Pointer;

                        compareLength = Math.Min(pEntry->KeyLength, searchKeyLength);
                        delta         = Native.memcmp(pLhs, pSearchKey, new UIntPtr(compareLength));
                    }
                }

                if (delta == 0)
                {
                    if (pEntry->KeyLength > searchKeyLength)
                    {
                        delta = 1;
                    }
                    else if (searchKeyLength > pEntry->KeyLength)
                    {
                        delta = -1;
                    }
                }

                if (delta == 0)
                {
                    resultIndex = (uint)pivot;
                    return(true);
                }
                else if (delta < 0)
                {
                    min = pivot + 1;
                }
                else
                {
                    max = pivot - 1;
                }
            }

            resultIndex = (uint)min;
            return(false);
        }
예제 #12
0
        public StreamRange LockValue(long nodeIndex, uint valueIndex, long?minimumSize, out BTreeValue *pValue, out ushort keyType)
        {
            var result = AccessNode(nodeIndex, true);

            unchecked {
                pValue = (BTreeValue *)(result.Pointer + BTreeNode.OffsetOfValues + (valueIndex * BTreeValue.Size));

                keyType         = pValue->KeyType;
                pValue->KeyType = 0;
            }

            var lockLength = pValue->DataLength;

            if ((minimumSize.HasValue) && (minimumSize.Value > lockLength))
            {
                lockLength = (uint)minimumSize.Value;

                var oldPosition = pValue->DataOffset;
                var oldLength   = pValue->DataLength + pValue->ExtraDataBytes;

                pValue->DataOffset     = (uint)AllocateDataSpace(ref lockLength).Value;
                pValue->ExtraDataBytes = (uint)(lockLength - oldLength);

                using (var oldDataRange = DataStream.AccessRange(oldPosition, oldLength))
                    using (var dataRange = DataStream.AccessRange(pValue->DataOffset, pValue->DataLength)) {
                        Native.memmove(dataRange.Pointer, oldDataRange.Pointer, new UIntPtr(pValue->DataLength));
                        Native.memset(oldDataRange.Pointer, 0, new UIntPtr(pValue->DataLength));
                    }

                FreelistPut(oldPosition, oldLength);
            }

            return(result);
        }