diff options
author | Nick Vatamaniuc <vatamane@apache.org> | 2019-08-22 15:53:15 -0400 |
---|---|---|
committer | Nick Vatamaniuc <nickva@users.noreply.github.com> | 2019-08-22 16:05:56 -0400 |
commit | ea1cba52f98f2404ebed40eb8f27aad7faa52bed (patch) | |
tree | a824bfb8dbf761511ede10794b90411e82909c7f | |
parent | 6d1a8d9895c2190e0c97f5bdcc3bd83aa3e7d511 (diff) | |
download | couchdb-ea1cba52f98f2404ebed40eb8f27aad7faa52bed.tar.gz |
Fix DB reopen behavior
Previously if a VDU was updated in the `before_doc_update/3` handlers, the Db
handle wasn't refreshed soon enough such that the `prepare_and_validate/3`
would not see the newly update VDU and would not run it.
To fix make a stale Db throws an exception which bubbles up all the way to
`fabric2_fdb:transactional/2` where the transaction is retried again with a
reopened Db.
During `reopen/1` make sure to properly transfer the `user_ctx` property to the
new handle, and also make sure `user_ctx` is removed from `db_options` to avoid
caching it in `fabric2_server`.
-rw-r--r-- | src/fabric/src/fabric2_fdb.erl | 36 |
1 files changed, 26 insertions, 10 deletions
diff --git a/src/fabric/src/fabric2_fdb.erl b/src/fabric/src/fabric2_fdb.erl index c58b5f674..df3709673 100644 --- a/src/fabric/src/fabric2_fdb.erl +++ b/src/fabric/src/fabric2_fdb.erl @@ -78,10 +78,22 @@ transactional(DbName, Options, Fun) when is_binary(DbName) -> transactional(#{tx := undefined} = Db, Fun) -> - #{layer_prefix := LayerPrefix} = Db, - do_transaction(fun(Tx) -> - Fun(Db#{tx => Tx}) - end, LayerPrefix); + try + Reopen = maps:get(reopen, Db, false), + Db1 = maps:remove(reopen, Db), + LayerPrefix = case Reopen of + true -> undefined; + false -> maps:get(layer_prefix, Db1) + end, + do_transaction(fun(Tx) -> + case Reopen of + true -> Fun(reopen(Db1#{tx => Tx})); + false -> Fun(Db1#{tx => Tx}) + end + end, LayerPrefix) + catch throw:{?MODULE, reopen} -> + transactional(Db#{reopen => true}, Fun) + end; transactional(#{tx := {erlfdb_transaction, _}} = Db, Fun) -> Fun(Db). @@ -150,6 +162,7 @@ create(#{} = Db0, Options) -> end, Defaults), UserCtx = fabric2_util:get_value(user_ctx, Options, #user_ctx{}), + Options1 = lists:keydelete(user_ctx, 1, Options), Db#{ uuid => UUID, @@ -165,7 +178,7 @@ create(#{} = Db0, Options) -> after_doc_read => undefined, % All other db things as we add features, - db_options => Options + db_options => Options1 }. @@ -186,6 +199,7 @@ open(#{} = Db0, Options) -> DbVersion = erlfdb:wait(erlfdb:get(Tx, DbVersionKey)), UserCtx = fabric2_util:get_value(user_ctx, Options, #user_ctx{}), + Options1 = lists:keydelete(user_ctx, 1, Options), Db2 = Db1#{ db_prefix => DbPrefix, @@ -201,7 +215,7 @@ open(#{} = Db0, Options) -> before_doc_update => undefined, after_doc_read => undefined, - db_options => Options + db_options => Options1 }, Db3 = lists:foldl(fun({Key, Val}, DbAcc) -> @@ -223,9 +237,11 @@ reopen(#{} = OldDb) -> #{ tx := Tx, name := DbName, - db_options := Options + db_options := Options, + user_ctx := UserCtx } = OldDb, - open(init_db(Tx, DbName, Options), Options). + Options1 = lists:keystore(user_ctx, 1, Options, {user_ctx, UserCtx}), + open(init_db(Tx, DbName, Options1), Options1). delete(#{} = Db) -> @@ -1132,7 +1148,7 @@ ensure_current(#{} = Db, CheckDbVersion) -> case erlfdb:wait(erlfdb:get(Tx, ?METADATA_VERSION_KEY)) of MetaDataVersion -> Db; - _NewVersion -> reopen(Db) + _NewVersion -> throw({?MODULE, reopen}) end, AlreadyChecked = get(?PDICT_CHECKED_DB_IS_CURRENT), @@ -1150,7 +1166,7 @@ ensure_current(#{} = Db, CheckDbVersion) -> Db; _NewDBVersion -> fabric2_server:remove(maps:get(name, Db)), - reopen(Db) + throw({?MODULE, reopen}) end end. |