summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Vatamaniuc <vatamane@apache.org>2019-08-22 15:53:15 -0400
committerNick Vatamaniuc <nickva@users.noreply.github.com>2019-08-22 16:05:56 -0400
commitea1cba52f98f2404ebed40eb8f27aad7faa52bed (patch)
treea824bfb8dbf761511ede10794b90411e82909c7f
parent6d1a8d9895c2190e0c97f5bdcc3bd83aa3e7d511 (diff)
downloadcouchdb-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.erl36
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.