couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dav...@apache.org
Subject [couchdb] 01/02: Prevent a terrible race condition
Date Thu, 13 Jul 2017 15:46:03 GMT
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 764168c5b03f17b7adfa5db9a3b7341b01281f44
Author: Paul J. Davis <paul.joseph.davis@gmail.com>
AuthorDate: Wed Jul 12 15:50:17 2017 -0500

    Prevent a terrible race condition
    
    Looking into #649 I realized there's a pretty terrible race condition if
    an index is compacted quickly followed by an index update. Since we
    don't check the index updater message it would be possible for us to
    swap out a compaction change, followed by immediately resetting to the
    new state from the index updater. This would be bad as we'd possibly end
    up with a situation where our long lived index would be operating on a
    file that no longer existed on disk.
---
 src/couch_index/src/couch_index.erl | 49 +++++++++++++++++++++++--------------
 1 file changed, 31 insertions(+), 18 deletions(-)

diff --git a/src/couch_index/src/couch_index.erl b/src/couch_index/src/couch_index.erl
index 9da928d..604d503 100644
--- a/src/couch_index/src/couch_index.erl
+++ b/src/couch_index/src/couch_index.erl
@@ -230,24 +230,37 @@ handle_cast({new_state, NewIdxState}, State) ->
         mod=Mod,
         idx_state=OldIdxState
     } = State,
-    assert_signature_match(Mod, OldIdxState, NewIdxState),
-    CurrSeq = Mod:get(update_seq, NewIdxState),
-    Args = [
-        Mod:get(db_name, NewIdxState),
-        Mod:get(idx_name, NewIdxState),
-        CurrSeq
-    ],
-    couch_log:debug("Updated index for db: ~s idx: ~s seq: ~B", Args),
-    Rest = send_replies(State#st.waiters, CurrSeq, NewIdxState),
-    case State#st.committed of
-        true -> erlang:send_after(commit_delay(), self(), commit);
-        false -> ok
-    end,
-    {noreply, State#st{
-        idx_state=NewIdxState,
-        waiters=Rest,
-        committed=false
-    }};
+    OldFd = Mod:get(fd, OldIdxState),
+    NewFd = Mod:get(fd, NewIdxState),
+    case NewFd == OldFd of
+        true ->
+            assert_signature_match(Mod, OldIdxState, NewIdxState),
+            CurrSeq = Mod:get(update_seq, NewIdxState),
+            Args = [
+                Mod:get(db_name, NewIdxState),
+                Mod:get(idx_name, NewIdxState),
+                CurrSeq
+            ],
+            couch_log:debug("Updated index for db: ~s idx: ~s seq: ~B", Args),
+            Rest = send_replies(State#st.waiters, CurrSeq, NewIdxState),
+            case State#st.committed of
+                true -> erlang:send_after(commit_delay(), self(), commit);
+                false -> ok
+            end,
+            {noreply, State#st{
+                idx_state=NewIdxState,
+                waiters=Rest,
+                committed=false
+            }};
+        false ->
+            Fmt = "Ignoring update from old indexer for db: ~s idx: ~s",
+            Args = [
+                Mod:get(db_name, NewIdxState),
+                Mod:get(idx_name, NewIdxState)
+            ],
+            couch_log:warning(Fmt, Args),
+            {noreply, State}
+    end;
 handle_cast({update_error, Error}, State) ->
     send_all(State#st.waiters, Error),
     {noreply, State#st{waiters=[]}};

-- 
To stop receiving notification emails like this one, please contact
"commits@couchdb.apache.org" <commits@couchdb.apache.org>.

Mime
View raw message