From d601c590ac4bc28eab628778fdccd75b2967a71a Mon Sep 17 00:00:00 2001 From: Nick Vatamaniuc Date: Fri, 8 Nov 2019 13:27:16 -0500 Subject: Before starting a db transanction, refresh the db handle from the cache Previously, a stale db handle could be re-used across a few separate transactions. That would result in the database getting re-opened before every one of those operations. To prevent that from happening, check the cache before the transaction starts, and if there is a newer version of the db handle and use that. --- src/fabric/src/fabric2_fdb.erl | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/src/fabric/src/fabric2_fdb.erl b/src/fabric/src/fabric2_fdb.erl index 1392ccd0f..1e370be95 100644 --- a/src/fabric/src/fabric2_fdb.erl +++ b/src/fabric/src/fabric2_fdb.erl @@ -82,16 +82,17 @@ transactional(DbName, Options, Fun) when is_binary(DbName) -> transactional(#{tx := undefined} = Db, Fun) -> try - Reopen = maps:get(reopen, Db, false), - Db1 = maps:remove(reopen, Db), + Db1 = refresh(Db), + Reopen = maps:get(reopen, Db1, false), + Db2 = maps:remove(reopen, Db1), LayerPrefix = case Reopen of true -> undefined; - false -> maps:get(layer_prefix, Db1) + false -> maps:get(layer_prefix, Db2) end, do_transaction(fun(Tx) -> case Reopen of - true -> Fun(reopen(Db1#{tx => Tx})); - false -> Fun(Db1#{tx => Tx}) + true -> Fun(reopen(Db2#{tx => Tx})); + false -> Fun(Db2#{tx => Tx}) end end, LayerPrefix) catch throw:{?MODULE, reopen} -> @@ -239,6 +240,27 @@ open(#{} = Db0, Options) -> load_validate_doc_funs(Db3). +refresh(#{tx := undefined, name := DbName, md_version := OldVer} = Db) -> + case fabric2_server:fetch(DbName) of + % Relying on these assumptions about the `md_version` value: + % - It is bumped every time `db_version` is bumped + % - Is a versionstamp, so we can check which one is newer + % - If it is `not_found`, it would sort less than a binary value + #{md_version := Ver} = Db1 when Ver > OldVer -> + Db1#{ + db_options := maps:get(db_options, Db), + user_ctx := maps:get(user_ctx, Db), + security_fun := maps:get(security_fun, Db) + }; + _ -> + Db + end; + +refresh(#{} = Db) -> + Db. + + + reopen(#{} = OldDb) -> require_transaction(OldDb), #{ -- cgit v1.2.1