From fade3d5b2a13192cf481244a2fb64bfa763996fa Mon Sep 17 00:00:00 2001 From: Marcus Denker Date: Wed, 17 Jan 2024 15:30:32 +0100 Subject: [PATCH] This PR adds a first test for #nextKeyCloseTo: (for now just with a transaction) - add #testNextKeyCloseToWithTransaction - fix on the iterator #nextKeyCloseTo: to return a value and move up to be usable for BTree, too - move some methods up in the page hierachy to make it work for BTree --- .../SoilIndexedDictionaryTest.class.st | 15 ++++++++++++++ src/Soil-Core/SoilIndexItemsPage.class.st | 20 +++++++++++++++++++ src/Soil-Core/SoilIndexIterator.class.st | 15 ++++++++++++++ src/Soil-Core/SoilIndexedDictionary.class.st | 5 +++++ src/Soil-Core/SoilSkipListIterator.class.st | 15 -------------- src/Soil-Core/SoilSkipListPage.class.st | 20 ------------------- 6 files changed, 55 insertions(+), 35 deletions(-) diff --git a/src/Soil-Core-Tests/SoilIndexedDictionaryTest.class.st b/src/Soil-Core-Tests/SoilIndexedDictionaryTest.class.st index b9797a37..ed8430f2 100644 --- a/src/Soil-Core-Tests/SoilIndexedDictionaryTest.class.st +++ b/src/Soil-Core-Tests/SoilIndexedDictionaryTest.class.st @@ -588,6 +588,21 @@ SoilIndexedDictionaryTest >> testNextAfterWithTransaction [ self assert: (tx2 root nextAfter: 1) value equals: #two ] +{ #category : #tests } +SoilIndexedDictionaryTest >> testNextKeyCloseToWithTransaction [ + | tx tx2 | + tx := soil newTransaction. + tx root: dict. + dict at: 10 put: #one. + dict at: 20 put: #two. + "self assert: dict last equals: #two." + tx commit. + "open a second transaction ..." + tx2 := soil newTransaction. + "and test last" + self assert: (tx2 root nextKeyCloseTo: 15) value equals: 20 +] + { #category : #tests } SoilIndexedDictionaryTest >> testRemoveKey [ dict at: #foo put: #bar. diff --git a/src/Soil-Core/SoilIndexItemsPage.class.st b/src/Soil-Core/SoilIndexItemsPage.class.st index ddb78bda..727f22c1 100644 --- a/src/Soil-Core/SoilIndexItemsPage.class.st +++ b/src/Soil-Core/SoilIndexItemsPage.class.st @@ -139,12 +139,32 @@ SoilIndexItemsPage >> items [ ^ items ] +{ #category : #accessing } +SoilIndexItemsPage >> keyOrClosestAfter: key [ + "find the closest key in this page. This returns the exact key if + present or the key that comes after. Else returns nil. This is useful if we enter the + list at an unknown point" + items isEmpty ifTrue: [ ^ nil ]. + self lastKey < key ifTrue: [ ^ nil ]. + ^ items + findBinaryIndex: [ :each | key - each key ] + do: [ :e | (items at: e) key] + ifNone: [ :a :b | + (items at: (b min: items size)) key ] +] + { #category : #accessing } SoilIndexItemsPage >> lastItem [ ^ items isNotEmpty ifTrue: [ items last ] ifFalse: [ nil ] ] +{ #category : #accessing } +SoilIndexItemsPage >> lastKey [ + + ^ items isNotEmpty ifTrue: [ items last key ] +] + { #category : #accessing } SoilIndexItemsPage >> numberOfItems [ ^ items size diff --git a/src/Soil-Core/SoilIndexIterator.class.st b/src/Soil-Core/SoilIndexIterator.class.st index 3b2604af..7f4cbdfa 100644 --- a/src/Soil-Core/SoilIndexIterator.class.st +++ b/src/Soil-Core/SoilIndexIterator.class.st @@ -284,6 +284,21 @@ SoilIndexIterator >> nextAssociation [ ^ nextValue ifNil: [ self nextAssociation ] ifNotNil: [ key -> nextValue ] ] +{ #category : #private } +SoilIndexIterator >> nextKeyCloseTo: key [ + + | binKey | + binKey := (key asSkipListKeyOfSize: index keySize) asInteger. + self findPageFor: binKey. + nextKey := currentPage keyOrClosestAfter: binKey. + ^ nextKey + ifNil: [ "if there is no close key found, we position the cursor at the end, so that asking for the next association will return nil" + currentKey := currentPage lastKey ] + ifNotNil: [ + "if there is a close key found, we make sure the cursor get properly positioned" + currentKey := nextKey ] +] + { #category : #accessing } SoilIndexIterator >> pageAt: anInteger [ ^ index store pageAt: anInteger diff --git a/src/Soil-Core/SoilIndexedDictionary.class.st b/src/Soil-Core/SoilIndexedDictionary.class.st index 85dd2fbc..eb9b3482 100644 --- a/src/Soil-Core/SoilIndexedDictionary.class.st +++ b/src/Soil-Core/SoilIndexedDictionary.class.st @@ -226,6 +226,11 @@ SoilIndexedDictionary >> nextAfter: key [ assoc key -> (transaction objectWithId: assoc value asSoilObjectId) ] ] +{ #category : #private } +SoilIndexedDictionary >> nextKeyCloseTo: aKey [ + ^ self newIterator nextKeyCloseTo: aKey +] + { #category : #private } SoilIndexedDictionary >> prepareNewValues [ newValues copy keysAndValuesDo: [ :key :object | diff --git a/src/Soil-Core/SoilSkipListIterator.class.st b/src/Soil-Core/SoilSkipListIterator.class.st index 6b1ef92d..3a851620 100644 --- a/src/Soil-Core/SoilSkipListIterator.class.st +++ b/src/Soil-Core/SoilSkipListIterator.class.st @@ -80,21 +80,6 @@ SoilSkipListIterator >> levelAt: anInteger [ ^ levels at: anInteger ] -{ #category : #private } -SoilSkipListIterator >> nextKeyCloseTo: key [ - - | binKey | - binKey := (key asSkipListKeyOfSize: index keySize) asInteger. - self findPageFor: binKey. - nextKey := currentPage keyOrClosestAfter: binKey. - nextKey - ifNil: [ "if there is no close key found, we position the cursor at the end, so that asking for the next association will return nil" - currentKey := currentPage lastKey ] - ifNotNil: [ - "if there is a close key found, we make sure the cursor get properly positioned" - currentKey := nextKey ] -] - { #category : #printing } SoilSkipListIterator >> printOn: aStream [ aStream << 'path: ' << levels asString diff --git a/src/Soil-Core/SoilSkipListPage.class.st b/src/Soil-Core/SoilSkipListPage.class.st index c2707b8f..38d85bfc 100644 --- a/src/Soil-Core/SoilSkipListPage.class.st +++ b/src/Soil-Core/SoilSkipListPage.class.st @@ -64,20 +64,6 @@ SoilSkipListPage >> isOlderThan: aVersionNumber [ ^ lastTransaction <= aVersionNumber ] -{ #category : #accessing } -SoilSkipListPage >> keyOrClosestAfter: key [ - "find the closest key in this page. This returns the exact key if - present or the key that comes after. Else returns nil. This is useful if we enter the - list at an unknown point" - items isEmpty ifTrue: [ ^ nil ]. - self lastKey < key ifTrue: [ ^ nil ]. - ^ items - findBinaryIndex: [ :each | key - each key ] - do: [ :e | (items at: e) key] - ifNone: [ :a :b | - (items at: (b min: items size)) key ] -] - { #category : #accessing } SoilSkipListPage >> keySize [ ^ keySize @@ -89,12 +75,6 @@ SoilSkipListPage >> keySize: anInteger [ keySize := anInteger. ] -{ #category : #accessing } -SoilSkipListPage >> lastKey [ - - ^ items isNotEmpty ifTrue: [ items last key ] -] - { #category : #accessing } SoilSkipListPage >> lastTransaction [ ^ lastTransaction