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); }
/// <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); }
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; }
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(); } } }
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); }
public void UnlockValue(BTreeValue *pEntry, ushort keyType) { unchecked { if (pEntry->KeyType != 0) { throw new InvalidDataException(); } pEntry->KeyType = keyType; } }
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>); }
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); }
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); }
public bool ReadKey(BTreeValue *pEntry, out TangleKey key) { ushort keyType = pEntry->KeyType; return(ReadKey(pEntry, keyType, out key)); }
/// <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); }
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); }