Skip to content

Commit 00941d2

Browse files
authored
fix: get latest version in store after legacy pruning fails (#1067)
1 parent 8a2e2fe commit 00941d2

File tree

2 files changed

+78
-1
lines changed

2 files changed

+78
-1
lines changed

nodedb.go

+38-1
Original file line numberDiff line numberDiff line change
@@ -724,7 +724,15 @@ func (ndb *nodeDB) deleteVersionsTo(toVersion int64) error {
724724
if err := ndb.deleteLegacyVersions(legacyLatestVersion); err != nil {
725725
ndb.logger.Error("Error deleting legacy versions", "err", err)
726726
}
727-
first = legacyLatestVersion + 1
727+
// NOTE: When pruning is broken for legacy versions we need to find the
728+
// latest non legacy version in the store
729+
// TODO: Make sure legacy pruning works as expected and does not fail
730+
firstNonLegacyVersion, err := ndb.getFirstNonLegacyVersion()
731+
if err != nil {
732+
return err
733+
}
734+
first = firstNonLegacyVersion
735+
728736
// reset the legacy latest version forcibly to avoid multiple calls
729737
ndb.resetLegacyLatestVersion(-1)
730738
}
@@ -766,6 +774,35 @@ func (ndb *nodeDB) legacyRootKey(version int64) []byte {
766774
return legacyRootKeyFormat.Key(version)
767775
}
768776

777+
// getFirstNonLegacyVersion binary searches the store for the first non-legacy version
778+
func (ndb *nodeDB) getFirstNonLegacyVersion() (int64, error) {
779+
ndb.mtx.Lock()
780+
firstVersion := ndb.firstVersion
781+
ndb.mtx.Unlock()
782+
783+
// Find the first version
784+
_, latestVersion, err := ndb.getLatestVersion()
785+
if err != nil {
786+
return 0, err
787+
}
788+
for firstVersion < latestVersion {
789+
version := (latestVersion + firstVersion) >> 1
790+
has, err := ndb.hasVersion(version)
791+
if err != nil {
792+
return 0, err
793+
}
794+
if has {
795+
latestVersion = version
796+
} else {
797+
firstVersion = version + 1
798+
}
799+
}
800+
801+
ndb.resetFirstVersion(latestVersion)
802+
803+
return latestVersion, nil
804+
}
805+
769806
func (ndb *nodeDB) getFirstVersion() (int64, error) {
770807
ndb.mtx.Lock()
771808
firstVersion := ndb.firstVersion

nodedb_test.go

+40
Original file line numberDiff line numberDiff line change
@@ -446,3 +446,43 @@ func TestCloseNodeDB(t *testing.T) {
446446
require.NoError(t, ndb.Close())
447447
require.NoError(t, ndb.Close()) // must not block or fail on second call
448448
}
449+
450+
func TestGetFirstNonLegacyVersion(t *testing.T) {
451+
db := dbm.NewMemDB()
452+
ndb := newNodeDB(db, 0, DefaultOptions(), NewNopLogger())
453+
454+
// Test case 1: Empty database
455+
firstVersion, err := ndb.getFirstNonLegacyVersion()
456+
require.NoError(t, err)
457+
require.Equal(t, int64(0), firstVersion)
458+
459+
// Test case 2: Database with only legacy versions
460+
// Create a legacy version at version 1
461+
legacyRoot := GetRootKey(1)
462+
require.NoError(t, ndb.batch.Set(ndb.legacyRootKey(1), legacyRoot))
463+
require.NoError(t, ndb.batch.Write())
464+
465+
firstVersion, err = ndb.getFirstNonLegacyVersion()
466+
require.NoError(t, err)
467+
require.Equal(t, int64(0), firstVersion)
468+
469+
// Test case 3: Database with both legacy and non-legacy versions
470+
// Create a non-legacy version at version 2
471+
nonLegacyRoot := GetRootKey(2)
472+
require.NoError(t, ndb.batch.Set(ndb.nodeKey(nonLegacyRoot), []byte{}))
473+
require.NoError(t, ndb.batch.Write())
474+
475+
firstVersion, err = ndb.getFirstNonLegacyVersion()
476+
require.NoError(t, err)
477+
require.Equal(t, int64(2), firstVersion)
478+
479+
// Test case 4: Database with multiple non-legacy versions
480+
// Create another non-legacy version at version 3
481+
nonLegacyRoot3 := GetRootKey(3)
482+
require.NoError(t, ndb.batch.Set(ndb.nodeKey(nonLegacyRoot3), []byte{}))
483+
require.NoError(t, ndb.batch.Write())
484+
485+
firstVersion, err = ndb.getFirstNonLegacyVersion()
486+
require.NoError(t, err)
487+
require.Equal(t, int64(2), firstVersion) // Should still return the first non-legacy version
488+
}

0 commit comments

Comments
 (0)