Skip to content

feat(provider/keystore): alt datastore wipe#1233

Open
guillaumemichel wants to merge 5 commits intomasterfrom
keystore/alt-datastore-wipe
Open

feat(provider/keystore): alt datastore wipe#1233
guillaumemichel wants to merge 5 commits intomasterfrom
keystore/alt-datastore-wipe

Conversation

@guillaumemichel
Copy link
Collaborator

@guillaumemichel guillaumemichel commented Feb 13, 2026

Context

The ResettableKeystore has a datastore where it stores keys that should be advertised to the DHT swarm. Its reset process takes a chan of the keys that should replace the existing ones, write them to a new datastore, and once it has read all the keys atomically swaps with the datastore previously in use. After the swap, the old datastore is cleared, all keys are individually removed.

Some datastore implementations (such as leveldb or pebble) don't reclaim the space straight away and simply add tombstones so that removed keys are collected during compaction at a later point. This leads to high disk usage since the swap process increases disk footprint by the keystore size at each reset operation, until compaction happens (usually on process shutdown).

This problem is tracked in ipfs/kubo#11096

Kubo companion PR ipfs/kubo#11198

Proposed fix

Instead of having a single datastore and use namespace.Wrap() to create the temporary datastore used for swap, we create and destroy datastores whenever needed. This allows reclaiming disk space as soon as the reset operation is over by removing the corresponding directory.

The main change is that the ResettableKeystore can be supplied with a datastore factory (create and destroy functions) instead of the datastore.

The old behavior remains possible, but it is now possible to use datastore factory for optimized disk footprint.

callers that need a prefix should wrap the datastore with
namespace.Wrap before passing it to WithDatastore.
Copy link
Member

@lidel lidel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Factory approach is good, but small leak(?) to fix below

Comment on lines 522 to 527
@@ -446,6 +525,23 @@ func (s *ResettableKeystore) Close() error {
if err = s.ds.Sync(context.Background(), sizeKey); err != nil {
return fmt.Errorf("error syncing size on close: %w", err)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm.. late on my end but if persistSize or Sync fails here, the early return will skip closing the factory-owned datastores at lines 530-543, and leak

perhaps wrap the factory close block in a defer at the top of the default branch, so it runs regardless of the early returns

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! ec4d653

@guillaumemichel
Copy link
Collaborator Author

There are 3 namespaces in used in the ResettableKeystore: /0, /1 and a meta datastore tracking active datastore and count of keys.

Updated so that the meta datastore isn't its own dedicated datastore, but has to be supplied to the constructor (to avoid a dedicated datastore file for storing 2 values).

@gammazero gammazero added the status/in-progress In progress label Mar 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants