private void InternalSetFoundValue(long nodeIndex, uint valueIndex, ref T value) { unchecked { _Version++; } using (var range = BTree.AccessNode(nodeIndex, true)) { ushort keyType; var pEntry = BTree.LockValue(range, valueIndex, out keyType); if (Indices.Count > 0) { TangleKey key; T oldValue; BTree.ReadKey(pEntry, keyType, out key); ReadData(ref *pEntry, keyType, out oldValue); foreach (var index in Indices.Values) { index.OnValueRemoved(key, ref oldValue); index.OnValueAdded(key, ref value); } } var segment = BTree.Serialize(pEntry, Serializer, keyType, ref value); BTree.WriteData(pEntry, segment); BTree.UnlockValue(pEntry, keyType); BTree.UnlockNode(range); } }
internal unsafe void UpdateIndexForEntry(TangleKey key, ref TValue value, bool add) { long nodeIndex; uint valueIndex; IEnumerable <TIndexKey> sequence; if (IndexFunction != null) { sequence = new IndexFunctionAdapter <TIndexKey, TValue>( IndexFunction, ref value ); } else { sequence = IndexMultipleFunction(value); } foreach (var synthesizedValue in sequence) { TangleKey synthesizedKey = KeyConverter(synthesizedValue); bool foundExisting = BTree.FindKey(synthesizedKey, true, out nodeIndex, out valueIndex); StreamRange range; if (foundExisting) { range = BTree.AccessNode(nodeIndex, true); } else if (add) { range = BTree.PrepareForInsert(nodeIndex, valueIndex); } else { throw new InvalidOperationException(); } long minimumSize; using (range) { if (!foundExisting) { BTree.WriteNewKey(range, valueIndex, synthesizedKey); } minimumSize = BTree.GetValueDataTotalBytes( range, valueIndex, foundExisting ? synthesizedKey.OriginalTypeId : (ushort)0 ); } if (foundExisting) { BTree.UnlockNode(range); } else { BTree.FinalizeInsert(range); } if (add) { // Ensure we will have enough room to insert this key, if necessary if (minimumSize == 0) { minimumSize = 4; } minimumSize += 6 + key.Data.Count; } BTreeValue *pValue; ushort lockedKeyType; fixed(byte *pKeyBytes = &key.Data.Array[key.Data.Offset]) using (var indexRange = BTree.LockValue(nodeIndex, valueIndex, minimumSize, out pValue, out lockedKeyType)) using (var dataRange = BTree.DataStream.AccessRange(pValue->DataOffset, (uint)minimumSize)) { if ((pValue->DataLength < 4)) { pValue->ExtraDataBytes -= (4 - pValue->DataLength); pValue->DataLength = 4; *(int *)dataRange.Pointer = 0; } int numKeys = *(int *)dataRange.Pointer; uint offset = 4; uint?keyPosition = null, totalKeySize = null; for (int i = 0; i < numKeys; i++) { int keyLength = *(int *)(dataRange.Pointer + offset); offset += 4; ushort comparisonKeyType = *(ushort *)(dataRange.Pointer + offset); offset += 2; if ((comparisonKeyType == key.OriginalTypeId) && (Native.memcmp( dataRange.Pointer + offset, pKeyBytes, new UIntPtr((uint)Math.Min(key.Data.Count, keyLength)) ) == 0)) { keyPosition = offset - 6; totalKeySize = (uint)(6 + keyLength); break; } offset += (uint)keyLength; } if (add) { if (!keyPosition.HasValue) { // Add the key at the end of the list var insertPosition = pValue->DataLength; if ((pValue->DataLength + pValue->ExtraDataBytes) < (insertPosition + 6 + key.Data.Count)) { throw new InvalidDataException(); } *(int *)(dataRange.Pointer + insertPosition) = key.Data.Count; *(ushort *)(dataRange.Pointer + insertPosition + 4) = key.OriginalTypeId; Native.memmove( dataRange.Pointer + insertPosition + 6, pKeyBytes, new UIntPtr((uint)key.Data.Count) ); pValue->DataLength += (uint)(6 + key.Data.Count); pValue->ExtraDataBytes -= (uint)(6 + key.Data.Count); *(int *)dataRange.Pointer += 1; } } else if (keyPosition.HasValue) { // Remove the key by moving the items after it back in the list var moveSize = dataRange.Size - (keyPosition.Value + totalKeySize); if (moveSize > 0) { Native.memmove( dataRange.Pointer + keyPosition.Value, dataRange.Pointer + keyPosition.Value + totalKeySize.Value, new UIntPtr((uint)moveSize) ); } pValue->DataLength -= (uint)(6 + key.Data.Count); pValue->ExtraDataBytes += (uint)(6 + key.Data.Count); *(int *)dataRange.Pointer -= 1; } BTree.UnlockValue(pValue, synthesizedKey.OriginalTypeId); BTree.UnlockNode(indexRange); } } if (add) { BTree.MutationSentinel += 1; } else { BTree.MutationSentinel -= 1; } }