public void Braking_large_allocation_in_scratch_file_has_to_really_create_separate_pages_of_size_one() { long pageNumber; using (var tx = Env.WriteTransaction()) { var section = ActiveRawDataSmallSection.Create(tx, "test", (byte)TableType.None); pageNumber = section.PageNumber; tx.Commit(); } using (var tx = Env.WriteTransaction()) { // just to increment transaction id tx.LowLevelTransaction.ModifyPage(0); tx.Commit(); } using (var tx = Env.WriteTransaction()) { var section = new ActiveRawDataSmallSection(tx, pageNumber); section.DeleteSection(pageNumber); var allocatePage = tx.LowLevelTransaction.AllocatePage(1); // the case is that the free space handling will return same page number as we just freed by deleting raw data section // if the below assertion fails it means we have changed voron internals and this test might require adjustments Assert.Equal(allocatePage.PageNumber, pageNumber); tx.Commit(); } Env.FlushLogToDataFile(); using (var tx = Env.WriteTransaction()) { // just to increment transaction id tx.LowLevelTransaction.ModifyPage(0); tx.Commit(); } using (var tx = Env.WriteTransaction()) { // just to increment transaction id tx.LowLevelTransaction.ModifyPage(0); tx.Commit(); } using (var tx = Env.WriteTransaction()) { // ensure below call won't throw 'An item with the same key has already been added' // from ScratchBufferFile.BreakLargeAllocationToSeparatePages ActiveRawDataSmallSection.Create(tx, "test", (byte)TableType.None); tx.Commit(); } }
public void Delete(long id) { int size; var ptr = DirectRead(id, out size); if (ptr == null) { return; } var stats = (TableSchemaStats *)_tableTree.DirectAdd(TableSchema.Stats, sizeof(TableSchemaStats)); NumberOfEntries--; stats->NumberOfEntries = NumberOfEntries; DeleteValueFromIndex(id, new TableValueReader(ptr, size)); var largeValue = (id % _pageSize) == 0; if (largeValue) { var page = _tx.LowLevelTransaction.GetPage(id / _pageSize); var numberOfPages = _tx.LowLevelTransaction.DataPager.GetNumberOfOverflowPages(page.OverflowSize); for (int i = 0; i < numberOfPages; i++) { _tx.LowLevelTransaction.FreePage(page.PageNumber + i); } return; } var density = ActiveDataSmallSection.Free(id); if (ActiveDataSmallSection.Contains(id) || density > 0.5) { return; } var sectionPageNumber = ActiveDataSmallSection.GetSectionPageNumber(id); if (density > 0.15) { ActiveCandidateSection.Add(sectionPageNumber); return; } // move all the data to the current active section (maybe creating a new one // if this is busy) // if this is in the active candidate list, remove it so it cannot be reused if the current // active is full and need a new one ActiveCandidateSection.Delete(sectionPageNumber); var idsInSection = ActiveDataSmallSection.GetAllIdsInSectionContaining(id); foreach (var idToMove in idsInSection) { int itemSize; var pos = ActiveDataSmallSection.DirectRead(idToMove, out itemSize); var newId = AllocateFromSmallActiveSection(itemSize); OnDataMoved(idToMove, newId, pos, itemSize); byte *writePos; if (ActiveDataSmallSection.TryWriteDirect(newId, itemSize, out writePos) == false) { throw new InvalidDataException($"Cannot write to newly allocated size in {Name} during delete"); } Memory.Copy(writePos, pos, itemSize); } ActiveDataSmallSection.DeleteSection(sectionPageNumber); }