Esempio n. 1
0
        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);
            }
        }
Esempio n. 2
0
        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;
            }
        }