diff options
-rw-r--r-- | src/couch/test/eunit/couchdb_views_tests.erl | 22 | ||||
-rw-r--r-- | src/couch/test/eunit/fixtures/6cf2c2f766f87b618edf6630b00f8736.view (renamed from src/couch/test/eunit/fixtures/3b835456c235b1827e012e25666152f3.view) | bin | 4192 -> 8310 bytes | |||
-rw-r--r-- | src/couch/test/eunit/fixtures/test.couch | bin | 16482 -> 28878 bytes | |||
-rw-r--r-- | src/couch_mrview/include/couch_mrview.hrl | 8 | ||||
-rw-r--r-- | src/couch_mrview/src/couch_mrview_index.erl | 17 | ||||
-rw-r--r-- | src/couch_mrview/src/couch_mrview_util.erl | 96 |
6 files changed, 71 insertions, 72 deletions
diff --git a/src/couch/test/eunit/couchdb_views_tests.erl b/src/couch/test/eunit/couchdb_views_tests.erl index d1aba8fd5..06e2f03eb 100644 --- a/src/couch/test/eunit/couchdb_views_tests.erl +++ b/src/couch/test/eunit/couchdb_views_tests.erl @@ -42,13 +42,14 @@ setup_legacy() -> DbName = <<"test">>, DbFileName = "test.couch", OldDbFilePath = filename:join([?FIXTURESDIR, DbFileName]), - OldViewName = "3b835456c235b1827e012e25666152f3.view", + OldViewName = "6cf2c2f766f87b618edf6630b00f8736.view", FixtureViewFilePath = filename:join([?FIXTURESDIR, OldViewName]), - NewViewName = "6cf2c2f766f87b618edf6630b00f8736.view", + NewViewName = "a1c5929f912aca32f13446122cc6ce50.view", DbDir = config:get("couchdb", "database_dir"), ViewDir = config:get("couchdb", "view_index_dir"), - OldViewFilePath = filename:join([ViewDir, ".test_design", OldViewName]), + OldViewFilePath = filename:join([ViewDir, ".test_design", "mrview", + OldViewName]), NewViewFilePath = filename:join([ViewDir, ".test_design", "mrview", NewViewName]), @@ -192,28 +193,31 @@ should_upgrade_legacy_view_files({DbName, Files}) -> % ensure old header OldHeader = read_header(OldViewFilePath), - ?assertMatch(#index_header{}, OldHeader), + ?assertEqual(6, tuple_size(OldHeader)), + ?assertMatch(mrheader, element(1, OldHeader)), % query view for expected results Rows0 = query_view(DbName, "test", "test"), - ?assertEqual(2, length(Rows0)), + ?assertEqual(3, length(Rows0)), % ensure old file gone ?assertNot(filelib:is_regular(OldViewFilePath)), % add doc to trigger update - DocUrl = db_url(DbName) ++ "/boo", + DocUrl = db_url(DbName) ++ "/bar", {ok, _, _, _} = test_request:put( - DocUrl, [{"Content-Type", "application/json"}], <<"{\"a\":3}">>), + DocUrl, [{"Content-Type", "application/json"}], <<"{\"a\":4}">>), % query view for expected results Rows1 = query_view(DbName, "test", "test"), - ?assertEqual(3, length(Rows1)), + ?assertEqual(4, length(Rows1)), % ensure new header timer:sleep(2000), % have to wait for awhile to upgrade the index NewHeader = read_header(NewViewFilePath), - ?assertMatch(#mrheader{}, NewHeader) + ?assertMatch(#mrheader{}, NewHeader), + NewViewStatus = hd(NewHeader#mrheader.view_states), + ?assertEqual(3, tuple_size(NewViewStatus)) end). diff --git a/src/couch/test/eunit/fixtures/3b835456c235b1827e012e25666152f3.view b/src/couch/test/eunit/fixtures/6cf2c2f766f87b618edf6630b00f8736.view Binary files differindex 9c67648be..a5668eeaa 100644 --- a/src/couch/test/eunit/fixtures/3b835456c235b1827e012e25666152f3.view +++ b/src/couch/test/eunit/fixtures/6cf2c2f766f87b618edf6630b00f8736.view diff --git a/src/couch/test/eunit/fixtures/test.couch b/src/couch/test/eunit/fixtures/test.couch Binary files differindex 32c79af32..5347a222f 100644 --- a/src/couch/test/eunit/fixtures/test.couch +++ b/src/couch/test/eunit/fixtures/test.couch diff --git a/src/couch_mrview/include/couch_mrview.hrl b/src/couch_mrview/include/couch_mrview.hrl index 29fe52bdb..bb0ab0b46 100644 --- a/src/couch_mrview/include/couch_mrview.hrl +++ b/src/couch_mrview/include/couch_mrview.hrl @@ -18,13 +18,10 @@ idx_name, language, design_opts=[], - seq_indexed=false, - keyseq_indexed=false, partitioned=false, lib, views, id_btree=nil, - log_btree=nil, update_seq=0, purge_seq=0, first_build, @@ -44,10 +41,6 @@ reduce_funs=[], def, btree=nil, - seq_btree=nil, - key_byseq_btree=nil, - seq_indexed=false, - keyseq_indexed=false, options=[] }). @@ -56,7 +49,6 @@ seq=0, purge_seq=0, id_btree_state=nil, - log_btree_state=nil, view_states=nil }). diff --git a/src/couch_mrview/src/couch_mrview_index.erl b/src/couch_mrview/src/couch_mrview_index.erl index 93994a09c..8542cc63f 100644 --- a/src/couch_mrview/src/couch_mrview_index.erl +++ b/src/couch_mrview/src/couch_mrview_index.erl @@ -94,15 +94,19 @@ open(Db, State0) -> } = State = set_partitioned(Db, State0), IndexFName = couch_mrview_util:index_file(DbName, Sig), - % If we are upgrading from <=1.2.x, we upgrade the view + % If we are upgrading from <= 2.x, we upgrade the view % index file on the fly, avoiding an index reset. + % We are making commit with a new state + % right after the upgrade to ensure + % that we have a proper sig in the header + % when open the view next time % % OldSig is `ok` if no upgrade happened. % - % To remove suppport for 1.2.x auto-upgrades in the + % To remove support for 2.x auto-upgrades in the % future, just remove the next line and the code - % between "upgrade code for <= 1.2.x" and - % "end upgrade code for <= 1.2.x" and the corresponding + % between "upgrade code for <= 2.x" and + % "end of upgrade code for <= 2.x" and the corresponding % code in couch_mrview_util OldSig = couch_mrview_util:maybe_update_index_file(State), @@ -110,13 +114,14 @@ open(Db, State0) -> case couch_mrview_util:open_file(IndexFName) of {ok, Fd} -> case couch_file:read_header(Fd) of - % upgrade code for <= 1.2.x + % upgrade code for <= 2.x {ok, {OldSig, Header}} -> % Matching view signatures. NewSt = couch_mrview_util:init_state(Db, Fd, State, Header), + ok = commit(NewSt), ensure_local_purge_doc(Db, NewSt), {ok, NewSt}; - % end of upgrade code for <= 1.2.x + % end of upgrade code for <= 2.x {ok, {Sig, Header}} -> % Matching view signatures. NewSt = couch_mrview_util:init_state(Db, Fd, State, Header), diff --git a/src/couch_mrview/src/couch_mrview_util.erl b/src/couch_mrview/src/couch_mrview_util.erl index c8bdfaf50..d0d2b3949 100644 --- a/src/couch_mrview/src/couch_mrview_util.erl +++ b/src/couch_mrview/src/couch_mrview_util.erl @@ -276,19 +276,6 @@ init_state(Db, Fd, #mrst{views=Views}=State, nil) -> view_states=[make_view_state(#mrview{}) || _ <- Views] }, init_state(Db, Fd, State, Header); -% read <= 1.2.x header record and transpile it to >=1.3.x -% header record -init_state(Db, Fd, State, #index_header{ - seq=Seq, - purge_seq=PurgeSeq, - id_btree_state=IdBtreeState, - view_states=ViewStates}) -> - init_state(Db, Fd, State, #mrheader{ - seq=Seq, - purge_seq=PurgeSeq, - id_btree_state=IdBtreeState, - view_states=[make_view_state(V) || V <- ViewStates] - }); init_state(Db, Fd, State, Header) -> #mrst{ language=Lang, @@ -299,7 +286,7 @@ init_state(Db, Fd, State, Header) -> purge_seq=PurgeSeq, id_btree_state=IdBtreeState, view_states=ViewStates - } = Header, + } = maybe_update_header(Header), IdBtOpts = [ {compression, couch_compress:get_compression_method()} @@ -951,30 +938,18 @@ mrverror(Mesg) -> throw({query_parse_error, Mesg}). -%% Updates 1.2.x or earlier view files to 1.3.x or later view files -%% transparently, the first time the 1.2.x view file is opened by -%% 1.3.x or later. +%% Updates 2.x view files to 3.x or later view files +%% transparently, the first time the 2.x view file is opened by +%% 3.x or later. %% %% Here's how it works: %% %% Before opening a view index, %% If no matching index file is found in the new location: -%% calculate the <= 1.2.x view signature +%% calculate the <= 2.x view signature %% if a file with that signature lives in the old location %% rename it to the new location with the new signature in the name. %% Then proceed to open the view index as usual. -%% After opening, read its header. -%% -%% If the header matches the <= 1.2.x style #index_header record: -%% upgrade the header to the new #mrheader record -%% The next time the view is used, the new header is used. -%% -%% If we crash after the rename, but before the header upgrade, -%% the header upgrade is done on the next view opening. -%% -%% If we crash between upgrading to the new header and writing -%% that header to disk, we start with the old header again, -%% do the upgrade and write to disk. maybe_update_index_file(State) -> DbName = State#mrst.db_name, @@ -990,10 +965,10 @@ maybe_update_index_file(State) -> end. update_index_file(State) -> - Sig = sig_vsn_12x(State), + Sig = sig_vsn_2x(State), DbName = State#mrst.db_name, FileName = couch_index_util:hexsig(Sig) ++ ".view", - IndexFile = couch_index_util:index_file("", DbName, FileName), + IndexFile = couch_index_util:index_file("mrview", DbName, FileName), % If we have an old index, rename it to the new position. case file:read_file_info(IndexFile) of @@ -1002,40 +977,63 @@ update_index_file(State) -> % If the target exists, e.g. the next request will find the % new file and we are good. We might need to catch this % further up to avoid a full server crash. - couch_log:info("Attempting to update legacy view index file.", []), NewIndexFile = index_file(DbName, State#mrst.sig), + couch_log:notice("Attempting to update legacy view index file" + " from ~p to ~s", [IndexFile, NewIndexFile]), ok = filelib:ensure_dir(NewIndexFile), ok = file:rename(IndexFile, NewIndexFile), - couch_log:info("Successfully updated legacy view index file.", []), + couch_log:notice("Successfully updated legacy view index file" + " ~s", [IndexFile]), Sig; - _ -> + {error, enoent} -> % Ignore missing index file + ok; + {error, Reason} -> + couch_log:error("Failed to update legacy view index file" + " ~s : ~s", [IndexFile, file:format_error(Reason)]), ok end. -sig_vsn_12x(State) -> - ViewInfo = [old_view_format(V) || V <- State#mrst.views], - SigData = case State#mrst.lib of - {[]} -> - {ViewInfo, State#mrst.language, State#mrst.design_opts}; - _ -> - {ViewInfo, State#mrst.language, State#mrst.design_opts, - couch_index_util:sort_lib(State#mrst.lib)} - end, - couch_hash:md5_hash(term_to_binary(SigData)). +sig_vsn_2x(State) -> + #mrst{ + lib = Lib, + language = Language, + design_opts = DesignOpts + } = State, + SI = proplists:get_value(<<"seq_indexed">>, DesignOpts, false), + KSI = proplists:get_value(<<"keyseq_indexed">>, DesignOpts, false), + Views = [old_view_format(V, SI, KSI) || V <- State#mrst.views], + SigInfo = {Views, Language, DesignOpts, couch_index_util:sort_lib(Lib)}, + couch_hash:md5_hash(term_to_binary(SigInfo)). -old_view_format(View) -> +old_view_format(View, SI, KSI) -> { - view, + mrview, View#mrview.id_num, + View#mrview.update_seq, + View#mrview.purge_seq, View#mrview.map_names, + View#mrview.reduce_funs, View#mrview.def, View#mrview.btree, - View#mrview.reduce_funs, + nil, + nil, + SI, + KSI, View#mrview.options }. -%% End of <= 1.2.x upgrade code. +maybe_update_header(#mrheader{} = Header) -> + Header; +maybe_update_header(Header) when tuple_size(Header) == 6 -> + #mrheader{ + seq = element(2, Header), + purge_seq = element(3, Header), + id_btree_state = element(4, Header), + view_states = [make_view_state(S) || S <- element(6, Header)] + }. + +%% End of <= 2.x upgrade code. make_view_state(#mrview{} = View) -> BTState = get_btree_state(View#mrview.btree), |