You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by va...@apache.org on 2019/08/22 20:02:33 UTC

[couchdb] 01/01: Fix DB reopen behavior

This is an automated email from the ASF dual-hosted git repository.

vatamane pushed a commit to branch prototype/fdb-layer-fix-db-reopen
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit a7bd1f6cda2198672ded096ee49b5ad32403d8b9
Author: Nick Vatamaniuc <va...@apache.org>
AuthorDate: Thu Aug 22 15:53:15 2019 -0400

    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`.
---
 src/fabric/src/fabric2_fdb.erl | 36 ++++++++++++++++++++++++++----------
 1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/src/fabric/src/fabric2_fdb.erl b/src/fabric/src/fabric2_fdb.erl
index c58b5f6..df37096 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.