summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Vatamaniuc <vatamane@apache.org>2019-11-08 13:27:16 -0500
committerNick Vatamaniuc <vatamane@apache.org>2019-11-08 13:47:59 -0500
commitd601c590ac4bc28eab628778fdccd75b2967a71a (patch)
treee0615f9fc08d8c89c7d9fa77e8d0fd4d51cc2f7a
parent1a0f6c0404c1c62adf968ed45a39f75a919485c5 (diff)
downloadcouchdb-check-security-in-transaction.tar.gz
Before starting a db transanction, refresh the db handle from the cachecheck-security-in-transaction
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.
-rw-r--r--src/fabric/src/fabric2_fdb.erl32
1 files 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),
#{