Skip to content

Conversation

jyeshe
Copy link

@jyeshe jyeshe commented Aug 21, 2025

What

Copies the entries from one store to another using hb_store behaviour (in a store agnostic way).

Note on scope: this implementation was tested only on local stores, more specifically syncing from hb_store_fs to hb_store_lmdb

Why

Use cases from FOR-139:

  • Migrating data between different store implementations
  • Creating backups of store data
  • Synchronizing stores across different environments

How to use

FromStore = #{~"store-module" => hb_store_fs, ~"name" => ~"cache-mainnet", ~"resolve" => false}.
ToStore = #{~"store-module" => hb_store_lmdb, ~"name" => ~"cache-mainnet"}.
hb_store:sync(FromStore, ToStore).

Validation steps

  1. Comment the ?DEFAULT_PRIMARY_STORE in hb_opts:default_message
  2. rm -rf cache-*
  3. Start HyperBEAM and hydrate a process (e.g. S5iWl7L76dBpvrm-i_SRWODchdLYBGwYeSrIxC8v-vI)
  4. Stop HyperBEAM
  5. Uncomment ?DEFAULT_PRIMARY_STORE and restart HyperBEAM
  6. Run the commands below (where resolve=false is used to allow syncing links):
1> FromFsStore = #{~"store-module" => hb_store_fs, ~"name" => ~"cache-mainnet", ~"resolve" => false}.
#{<<"name">> => <<"cache-mainnet">>,<<"resolve">> => false,
  <<"store-module">> => hb_store_fs}
2> ToLmdbStore = #{~"store-module" => hb_store_lmdb, ~"name" => ~"cache-mainnet"}.
#{<<"name">> => <<"cache-mainnet">>,
  <<"store-module">> => hb_store_lmdb}
3> hb_store:sync(FromFsStore, ToLmdbStore).
ok
4> FsStore = #{~"store-module" => hb_store_fs, ~"name" => ~"cache-mainnet"}.
#{<<"name">> => <<"cache-mainnet">>,
  <<"store-module">> => hb_store_fs}
5> {ok, FsEntries} = hb_store:list(FsStore, "/"), length(FsEntries).
35934
6> Groups = [X || X <- FsEntries, composite == hb_store:type(ToLmdbStore, X)], length(Groups).
35931
7> NotGroups = [X || X <- FsEntries, composite =/= hb_store:type(ToLmdbStore, X)], length(NotGroups).
3
8> Paths = [<<G/binary, "/", F/binary>> || G <- Groups, F <- element(2, hb_store:list(ToLmdbStore, G))], hd(Paths).
<<"lY1jQ7wKCS10hTAsbbValARN1TzFEf4glHdnl3eSFtE/name">>
9> SimplePaths = [P || P <- Paths, hb_store:type(ToLmdbStore, P) == simple], length(SimplePaths).
263456
10> [SP || SP <- SimplePaths, hb_store:read(ToLmdbStore, SP) =/= hb_store:read(FsStore, SP)].
[] 
11> ProcAssignments = ~"assignments/S5iWl7L76dBpvrm-i_SRWODchdLYBGwYeSrIxC8v-vI/".
12> Slots = [<<ProcAssignments/binary, S/binary>> || S <- element(2, hb_store:list(ToLmdbStore, ProcAssignments))], length(Slots).
1151
13> {hd(Slots), lists:last(Slots), hb_store:type(ToLmdbStore, <<ProcAssignments/binary, "1150">>)}.
{<<"assignments/S5iWl7L76dBpvrm-i_SRWODchdLYBGwYeSrIxC8v-vI/0">>,
 <<"assignments/S5iWl7L76dBpvrm-i_SRWODchdLYBGwYeSrIxC8v-vI/999">>,
 composite}
14> SlotListings = [<<S/binary, "/", L/binary>> || S <- Slots, L <- element(2, hb_store:list(ToLmdbStore, S))], hd(SlotListings).
<<"assignments/S5iWl7L76dBpvrm-i_SRWODchdLYBGwYeSrIxC8v-vI/0/ao-types">>
15> [SL || SL <- SlotListings, hb_store:read(ToLmdbStore, SL) =/= hb_store:read(FsStore, SL)].
[]

Addtional Notes

TBD:

  • How to deal with retries when sync returns {error, {sync_failed, FailedKeyValues}}
  • How to sync stores in different nodes/machines

@jyeshe jyeshe force-pushed the for139/store-sync branch from f02d4b7 to b400f52 Compare August 22, 2025 21:33
@jyeshe
Copy link
Author

jyeshe commented Aug 25, 2025

Reading nested paths (e.g slots entries) was not working because link targets are returned with a leading /.
In this print we can see the slot 0 from hydrated process S5iWl7L76dBpvrm-i_SRWODchdLYBGwYeSrIxC8v-vI was not_found while it was pointing to a entry having a leading "/".

image

@jyeshe jyeshe force-pushed the for139/store-sync branch from 4069cdd to 929fe3f Compare August 25, 2025 18:06
@jyeshe jyeshe marked this pull request as ready for review August 25, 2025 19:20
@jyeshe jyeshe requested a review from twilson63 August 25, 2025 19:20
ok;
call_all([Store = #{<<"store-module">> := Mod} | Rest], Function, Args) ->
try apply_store_function(Mod, Function, Store, Args)
try apply_store_function(Mod, Store, Function, Args)
Copy link
Author

Choose a reason for hiding this comment

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

Formatter agent merit

jyeshe and others added 11 commits October 6, 2025 12:36
* refactor: allow store shallow reads for links

* refactor: rename symlink to link

More generic for stores other than hb_store_fs

* fix: prevent resolve on hb_store_fs:read with follow-link false

* refactor: rename follow-link to resolve

We just needed to skip resolve on the previous commit to get the link destination path instead of its content
@jyeshe jyeshe force-pushed the for139/store-sync branch from 22dc07a to cf54786 Compare October 6, 2025 11:36
@jyeshe jyeshe changed the base branch from edge to omni/m3-b3 October 6, 2025 11:37
@jyeshe
Copy link
Author

jyeshe commented Oct 6, 2025

% rebar3 eunit --module=hb_store_lmdb
...
All 17 tests passed.
% rebar3 eunit --module=hb_store
...
All 32 tests passed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant