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)); }
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)); }
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); }
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); }
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); }
/// <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); } }
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); }