summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Avdey <eiri@eiri.ca>2019-11-18 16:34:55 -0400
committerEric Avdey <eiri@eiri.ca>2019-12-03 13:54:40 -0400
commite1c66f2c0f5d5473df2727cf1a4a000b773ee11a (patch)
tree26a73b91892baed89f40b9f4b9f91df0868555f7
parent855afac1886514ffdaceb982e7f97a8b429cda7d (diff)
downloadcouchdb-2167-no-view-changes.tar.gz
Modify all mrview records and add according migration functionality2167-no-view-changes
-rw-r--r--src/couch/test/eunit/couchdb_views_tests.erl22
-rw-r--r--src/couch/test/eunit/fixtures/6cf2c2f766f87b618edf6630b00f8736.view (renamed from src/couch/test/eunit/fixtures/3b835456c235b1827e012e25666152f3.view)bin4192 -> 8310 bytes
-rw-r--r--src/couch/test/eunit/fixtures/test.couchbin16482 -> 28878 bytes
-rw-r--r--src/couch_mrview/include/couch_mrview.hrl8
-rw-r--r--src/couch_mrview/src/couch_mrview_index.erl17
-rw-r--r--src/couch_mrview/src/couch_mrview_util.erl96
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
index 9c67648be..a5668eeaa 100644
--- a/src/couch/test/eunit/fixtures/3b835456c235b1827e012e25666152f3.view
+++ b/src/couch/test/eunit/fixtures/6cf2c2f766f87b618edf6630b00f8736.view
Binary files differ
diff --git a/src/couch/test/eunit/fixtures/test.couch b/src/couch/test/eunit/fixtures/test.couch
index 32c79af32..5347a222f 100644
--- a/src/couch/test/eunit/fixtures/test.couch
+++ b/src/couch/test/eunit/fixtures/test.couch
Binary files differ
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),