Пример #1
0
        public long Update(long id, TableValueBuilder builder)
        {
            // The ids returned from this function MUST NOT be stored outside of the transaction.
            // These are merely for manipulation within the same transaction, and WILL CHANGE afterwards.
            int size = builder.Size;

            // first, try to fit in place, either in small or large sections
            var prevIsSmall = id % _pageSize != 0;

            if (size + sizeof(RawDataSection.RawDataEntrySizes) < ActiveDataSmallSection.MaxItemSize)
            {
                // We must read before we call TryWriteDirect, because it will modify the size
                int oldDataSize;
                var oldData = DirectRead(id, out oldDataSize);

                byte *pos;
                if (prevIsSmall && ActiveDataSmallSection.TryWriteDirect(id, size, out pos))
                {
                    DeleteValueFromIndex(id, new TableValueReader(oldData, oldDataSize));

                    // MemoryCopy into final position.
                    builder.CopyTo(pos);
                    InsertIndexValuesFor(id, new TableValueReader(pos, size));

                    return(id);
                }
            }
            else if (prevIsSmall == false)
            {
                var pageNumber            = id / _pageSize;
                var page                  = _tx.LowLevelTransaction.GetPage(pageNumber);
                var existingNumberOfPages = _tx.LowLevelTransaction.DataPager.GetNumberOfOverflowPages(page.OverflowSize);
                var newNumberOfPages      = _tx.LowLevelTransaction.DataPager.GetNumberOfOverflowPages(size);

                if (existingNumberOfPages == newNumberOfPages)
                {
                    page = _tx.LowLevelTransaction.ModifyPage(pageNumber);

                    page.OverflowSize = size;
                    var pos = page.Pointer + sizeof(PageHeader);

                    DeleteValueFromIndex(id, new TableValueReader(pos, size));

                    // MemoryCopy into final position.
                    builder.CopyTo(pos);

                    InsertIndexValuesFor(id, new TableValueReader(pos, size));

                    return(id);
                }
            }

            // can't fit in place, will just delete & insert instead
            Delete(id);
            return(Insert(builder));
        }
Пример #2
0
        public long Update(long id, TableValueBuilder builder)
        {
            int size = builder.Size;

            // first, try to fit in place, either in small or large sections
            var prevIsSmall = id % _pageSize != 0;

            if (size < ActiveDataSmallSection.MaxItemSize)
            {
                byte *pos;
                if (prevIsSmall && ActiveDataSmallSection.TryWriteDirect(id, size, out pos))
                {
                    int oldDataSize;
                    var oldData = ActiveDataSmallSection.DirectRead(id, out oldDataSize);

                    DeleteValueFromIndex(id, new TableValueReader(oldData, oldDataSize));

                    // MemoryCopy into final position.
                    builder.CopyTo(pos);
                    InsertIndexValuesFor(id, new TableValueReader(pos, size));

                    return(id);
                }
            }
            else if (prevIsSmall == false)
            {
                var pageNumber            = id / _pageSize;
                var page                  = _tx.LowLevelTransaction.GetPage(pageNumber);
                var existingNumberOfPages = _tx.LowLevelTransaction.DataPager.GetNumberOfOverflowPages(page.OverflowSize);
                var newNumberOfPages      = _tx.LowLevelTransaction.DataPager.GetNumberOfOverflowPages(size);

                if (existingNumberOfPages == newNumberOfPages)
                {
                    page.OverflowSize = size;
                    var pos = page.Pointer + sizeof(PageHeader);

                    DeleteValueFromIndex(id, new TableValueReader(pos, size));

                    // MemoryCopy into final position.
                    builder.CopyTo(pos);

                    InsertIndexValuesFor(id, new TableValueReader(pos, size));

                    return(id);
                }
            }

            // can't fit in place, will just delete & insert instead
            Delete(id);
            return(Insert(builder));
        }
Пример #3
0
        public long Insert(TableValueBuilder builder)
        {
            // Any changes done to this method should be reproduced in the Insert below, as they're used when compacting.
            // The ids returned from this function MUST NOT be stored outside of the transaction.
            // These are merely for manipulation within the same transaction, and WILL CHANGE afterwards.
            var stats = (TableSchemaStats *)_tableTree.DirectAdd(TableSchema.StatsSlice, sizeof(TableSchemaStats));

            NumberOfEntries++;
            stats->NumberOfEntries = NumberOfEntries;

            int size = builder.Size;

            byte *pos;
            long  id;

            if (size + sizeof(RawDataSection.RawDataEntrySizes) < ActiveDataSmallSection.MaxItemSize)
            {
                id = AllocateFromSmallActiveSection(size);

                if (ActiveDataSmallSection.TryWriteDirect(id, size, out pos) == false)
                {
                    throw new InvalidOperationException($"After successfully allocating {size:#,#;;0} bytes, failed to write them on {Name}");
                }

                // Memory Copy into final position.
                builder.CopyTo(pos);
            }
            else
            {
                var numberOfOverflowPages = _tx.LowLevelTransaction.DataPager.GetNumberOfOverflowPages(size);
                var page = _tx.LowLevelTransaction.AllocatePage(numberOfOverflowPages);
                _overflowPageCount      += numberOfOverflowPages;
                stats->OverflowPageCount = _overflowPageCount;

                page.Flags        = PageFlags.Overflow | PageFlags.RawData;
                page.OverflowSize = size;

                pos = page.Pointer + sizeof(PageHeader);

                builder.CopyTo(pos);
                id = page.PageNumber * _pageSize;
            }

            InsertIndexValuesFor(id, new TableValueReader(pos, size));

            return(id);
        }
Пример #4
0
        public long Insert(TableValueBuilder builder)
        {
            var stats = (TableSchemaStats *)_tableTree.DirectAdd(TableSchema.Stats, sizeof(TableSchemaStats));

            NumberOfEntries++;
            stats->NumberOfEntries = NumberOfEntries;


            int size = builder.Size;

            byte *pos;
            long  id;

            if (size + sizeof(RawDataSection.RawDataEntrySizes) < ActiveDataSmallSection.MaxItemSize)
            {
                id = AllocateFromSmallActiveSection(size);

                if (ActiveDataSmallSection.TryWriteDirect(id, size, out pos) == false)
                {
                    throw new InvalidOperationException($"After successfully allocating {size:#,#;;0} bytes, failed to write them on {Name}");
                }

                // MemoryCopy into final position.
                builder.CopyTo(pos);
            }
            else
            {
                var numberOfOverflowPages = _tx.LowLevelTransaction.DataPager.GetNumberOfOverflowPages(size);
                var page = _tx.LowLevelTransaction.AllocatePage(numberOfOverflowPages);
                page.Flags        = PageFlags.Overflow | PageFlags.RawData;
                page.OverflowSize = size;

                pos = page.Pointer + sizeof(PageHeader);

                builder.CopyTo(pos);

                id = page.PageNumber * _pageSize;
            }

            InsertIndexValuesFor(id, new TableValueReader(pos, size));

            return(id);
        }
Пример #5
0
            public byte[] Serialize()
            {
                var serializer = new TableValueBuilder
                {
                    StartIndex,
                    IsGlobal,
                    Name
                };

                byte[] serialized = new byte[serializer.Size];

                fixed(byte *destination = serialized)
                {
                    serializer.CopyTo(destination);
                }

                return(serialized);
            }
Пример #6
0
        /// <summary>
        /// Serializes structure into a byte array:
        ///
        ///  1. Whether the schema has a primary key
        ///  2. The primary key (if present)
        ///  3. Number of composite indexes
        ///  4. Values of the composite indexes
        ///  5. Number of fixed size indexes
        ///  6. Values of the fixed size indexes
        /// </summary>
        /// <returns></returns>
        internal byte[] SerializeSchema()
        {
            // Create list of serialized substructures
            var  structure     = new List <byte[]>();
            bool hasPrimaryKey = _primaryKey != null;

            structure.Add(BitConverter.GetBytes(hasPrimaryKey));

            if (hasPrimaryKey)
            {
                structure.Add(_primaryKey.Serialize());
            }

            structure.Add(BitConverter.GetBytes(_indexes.Count));
            structure.AddRange(_indexes.Values.Select(index => index.Serialize()));

            structure.Add(BitConverter.GetBytes(_fixedSizeIndexes.Count));
            structure.AddRange(_fixedSizeIndexes.Values.Select(index => index.Serialize()));

            var totalSize = structure.Select((bytes, i) => bytes.Length).Sum();
            var packed    = new byte[totalSize];
            int position  = 0;

            fixed(byte *ptr = packed)
            {
                var serializer = new TableValueBuilder();

                foreach (var member in structure)
                {
                    member.CopyTo(packed, position);
                    serializer.Add(&ptr[position], member.Length);
                    position += member.Length;
                }

                var output = new byte[serializer.Size];

                fixed(byte *outputPtr = output)
                {
                    serializer.CopyTo(outputPtr);
                }

                return(output);
            }
        }
Пример #7
0
            public byte[] Serialize()
            {
                // We serialize the Type enum as ulong to be "future-proof"
                var castedType = (long)Type;

                var serializer = new TableValueBuilder
                {
                    castedType,
                    StartIndex,
                    Count,
                    IsGlobal,
                    Name
                };

                byte[] serialized = new byte[serializer.Size];

                fixed(byte *destination = serialized)
                {
                    serializer.CopyTo(destination);
                }

                return(serialized);
            }