From fd14bcfa3cff03eb96ef7a75f87f5cc059799257 Mon Sep 17 00:00:00 2001 From: Marcus Denker Date: Wed, 23 Oct 2024 12:13:20 +0200 Subject: [PATCH] - more assertions in #testRemovePage ( - implement Dirty pages tracking for BTree - testRemovePagesSequential is now green for BTree --- src/Soil-Core-Tests/SoilBTreeTest.class.st | 15 +++++++-- .../SoilIndexedDictionaryTest.class.st | 12 +++++-- src/Soil-Core-Tests/SoilSkipListTest.class.st | 13 +++++++- src/Soil-Core/SoilBTree.class.st | 5 --- src/Soil-Core/SoilBTreeIterator.class.st | 2 +- src/Soil-Core/SoilBasicBTree.class.st | 32 ++++++++++++++++--- src/Soil-Core/SoilCopyOnWriteBTree.class.st | 4 +++ 7 files changed, 66 insertions(+), 17 deletions(-) diff --git a/src/Soil-Core-Tests/SoilBTreeTest.class.st b/src/Soil-Core-Tests/SoilBTreeTest.class.st index 6a5ab6c0..d359f825 100644 --- a/src/Soil-Core-Tests/SoilBTreeTest.class.st +++ b/src/Soil-Core-Tests/SoilBTreeTest.class.st @@ -503,7 +503,7 @@ SoilBTreeTest >> testRemoveKey [ { #category : #tests } SoilBTreeTest >> testRemovePage [ - | capacityFirst offset capacity iterator | + | capacityFirst offset capacity iterator counter | capacityFirst := index firstPage itemCapacity. 1 to: capacityFirst do: [ :n | index at: n put: (n asByteArrayOfSize: 8) ]. @@ -519,9 +519,18 @@ SoilBTreeTest >> testRemovePage [ self assert: index pages size equals: 13. index recyclePage: (index pages at: 3). self assert: index pages size equals: 13. + "page 3 is the recycled page" + self assert: index firstFreePage offset equals: 3. + "the page is a free page" + self assert: index firstFreePage class equals: SoilFreePage. "after, index 3 should not be a value in any index page item" - index indexPages do: [ :indexPage | self assert: (indexPage items noneSatisfy: [ :item | item value == 3 ]) ] - + index indexPages do: [ :indexPage | self assert: (indexPage items noneSatisfy: [ :item | item value == 3 ]) ]. + "if we follow the next pointer, we find only the non-recyled data pages" + iterator := index newIterator. + counter := 0. + iterator pagesDo: [ :page | counter := counter + 1]. + "13 - 1 indexPage - 1 recycled page" + self assert: counter equals: 11. ] { #category : #tests } diff --git a/src/Soil-Core-Tests/SoilIndexedDictionaryTest.class.st b/src/Soil-Core-Tests/SoilIndexedDictionaryTest.class.st index b8b3b395..f71a824c 100644 --- a/src/Soil-Core-Tests/SoilIndexedDictionaryTest.class.st +++ b/src/Soil-Core-Tests/SoilIndexedDictionaryTest.class.st @@ -694,20 +694,26 @@ SoilIndexedDictionaryTest >> testRemovePagesConcurrent [ { #category : #tests } SoilIndexedDictionaryTest >> testRemovePagesSequential [ | tx tx2 index indexManager | - (classToTest = SoilBTreeDictionary ) ifTrue: [ self skip ]. + tx := soil newTransaction. tx root: dict. 1 to: 1000 do: [ :n | dict at: n put: n asString ]. + tx commit. + "open a second transaction ..." tx2 := soil newTransaction. - 300 to: 700 do: [ :n | tx2 root removeKey: n ]. + "we remove all keys from one page to make it empty" + (classToTest = SoilBTreeDictionary) + ifTrue: [339 to: 451 do: [ :n | tx2 root removeKey: n ]] + ifFalse: [ 300 to: 700 do: [ :n | tx2 root removeKey: n ]]. + tx2 commit. indexManager := soil objectRepository firstSegment indexManager. index := indexManager indexes anyOne. self assert: index dirtyPages size equals: 0. self assert: indexManager dirtyIndexes size equals: 0. - self assert: (index pages select: #needsWrite) size equals: 1 + self assert: (index pages select: #needsWrite) size equals: ( (classToTest = SoilBTreeDictionary) ifTrue: [2] ifFalse: [1]) ] diff --git a/src/Soil-Core-Tests/SoilSkipListTest.class.st b/src/Soil-Core-Tests/SoilSkipListTest.class.st index 04c4d847..45185b3f 100644 --- a/src/Soil-Core-Tests/SoilSkipListTest.class.st +++ b/src/Soil-Core-Tests/SoilSkipListTest.class.st @@ -468,7 +468,7 @@ SoilSkipListTest >> testRemoveKey [ { #category : #tests } SoilSkipListTest >> testRemovePage [ - | capacityFirst offset capacity iterator | + | capacityFirst offset capacity iterator counter | capacityFirst := index firstPage itemCapacity. 1 to: capacityFirst do: [ :n | index at: n put: (n asByteArrayOfSize: 8) ]. @@ -484,6 +484,17 @@ SoilSkipListTest >> testRemovePage [ self assert: index pages size equals: 6. index recyclePage: (index pages at: 3). self assert: index pages size equals: 6. + + "page 3 is the recycled page" + self assert: index firstFreePage offset equals: 3. + "and it is a FreePage" + self assert: index firstFreePage class equals: SoilFreePage. + "if we follow the next pointer, we find only the non-recyled data pages" + iterator := index newIterator. + counter := 0. + iterator pagesDo: [ :page | counter := counter + 1]. + "6 minus 1 recycled page" + self assert: counter equals: 5 diff --git a/src/Soil-Core/SoilBTree.class.st b/src/Soil-Core/SoilBTree.class.st index 31683c72..c1bba0a7 100644 --- a/src/Soil-Core/SoilBTree.class.st +++ b/src/Soil-Core/SoilBTree.class.st @@ -25,11 +25,6 @@ SoilBTree >> destroy [ path ensureDelete ] -{ #category : #accessing } -SoilBTree >> dirtyPages [ - ^ #() -] - { #category : #testing } SoilBTree >> isRegistered [ ^ path notNil diff --git a/src/Soil-Core/SoilBTreeIterator.class.st b/src/Soil-Core/SoilBTreeIterator.class.st index d1d8ce21..23250777 100644 --- a/src/Soil-Core/SoilBTreeIterator.class.st +++ b/src/Soil-Core/SoilBTreeIterator.class.st @@ -19,7 +19,7 @@ SoilBTreeIterator >> basicAt: indexKey put: anObject [ possiblePriorValue returnValue ifNil: [ "only increase size if there was no prior value" index increaseSize]. - + index addDirtyPage: currentPage. ^ possiblePriorValue returnValue ] diff --git a/src/Soil-Core/SoilBasicBTree.class.st b/src/Soil-Core/SoilBasicBTree.class.st index d090a8f8..ddd15b66 100644 --- a/src/Soil-Core/SoilBasicBTree.class.st +++ b/src/Soil-Core/SoilBasicBTree.class.st @@ -8,6 +8,9 @@ See SoilBTree for more information Class { #name : #SoilBasicBTree, #superclass : #SoilIndex, + #instVars : [ + 'dirtyPages' + ], #category : #'Soil-Core-Index-BTree' } @@ -17,6 +20,11 @@ SoilBasicBTree class >> isAbstract [ ^ self == SoilBasicBTree ] +{ #category : #adding } +SoilBasicBTree >> addDirtyPage: aPage [ + dirtyPages add: aPage +] + { #category : #converting } SoilBasicBTree >> asCopyOnWrite [ ^ SoilCopyOnWriteBTree new @@ -29,6 +37,11 @@ SoilBasicBTree >> dataPages [ ^ (self pages reject: [ :page | page isIndexPage ]) asArray ] +{ #category : #accessing } +SoilBasicBTree >> dirtyPages [ + ^ dirtyPages +] + { #category : #accessing } SoilBasicBTree >> flush [ self store flush @@ -44,6 +57,12 @@ SoilBasicBTree >> indexPages [ ^ (self pages select: [ :page | page isIndexPage ]) asArray ] +{ #category : #initialization } +SoilBasicBTree >> initialize [ + super initialize. + dirtyPages := Set new +] + { #category : #initialization } SoilBasicBTree >> initializeFilesystem [ self store initializeFilesystem @@ -129,12 +148,17 @@ SoilBasicBTree >> recyclePage: aPage [ ^ self addToFreePages: aPage ] +{ #category : #removing } +SoilBasicBTree >> removeDirtyPage: aPage [ + dirtyPages remove: aPage +] + { #category : #removing } SoilBasicBTree >> removeKey: key ifAbsent: aBlock [ - | removedItem | - removedItem := self rootPage remove: key for: self. - removedItem ifNil: [aBlock value]. - ^removedItem value + + ^ (self rootPage remove: key for: self) + ifNil: [ aBlock value ] + ifNotNil: [ :removedItem | removedItem value ] ] { #category : #removing } diff --git a/src/Soil-Core/SoilCopyOnWriteBTree.class.st b/src/Soil-Core/SoilCopyOnWriteBTree.class.st index b1d094e0..ecca16bf 100644 --- a/src/Soil-Core/SoilCopyOnWriteBTree.class.st +++ b/src/Soil-Core/SoilCopyOnWriteBTree.class.st @@ -7,6 +7,10 @@ Class { #category : #'Soil-Core-Index-BTree' } +{ #category : #adding } +SoilCopyOnWriteBTree >> addDirtyPage: aPage [ +] + { #category : #'as yet unclassified' } SoilCopyOnWriteBTree >> allocatePage [ ^ self newPage