Permalink
Browse files

Add initial vclock to per node keys that changed since 1.6.5.

This change fixes MB-4219.

When config merging routines encounter two values not having vclocks
attached to them then the value that came from remote node is
chosen. This can cause certain races. Particularly this is the cause
of upgrade issues seen on windows: when node is started for the first
time it upgrades old config but then it pulls the config from other
nodes and prefers foreign value (outdated one) to its own. This change
introduces initial vclocks for such vulnerable keys so that new values
will be preferred.

Change-Id: Ibe85213eb8df2392f6b4b34413062c0aed19c0a1
Reviewed-on: http://review.couchbase.org/9206
Reviewed-by: Aliaksey Kandratsenka <alkondratenko@gmail.com>
Tested-by: Aliaksey Kandratsenka <alkondratenko@gmail.com>
  • Loading branch information...
1 parent 02ef5f3 commit 850003232fb2bc2ec1a7cc8862419a28cda4b456 @aartamonau aartamonau committed with alk Aug 24, 2011
Showing with 46 additions and 5 deletions.
  1. +46 −5 src/ns_config_default.erl
View
51 src/ns_config_default.erl
@@ -16,6 +16,7 @@
-module(ns_config_default).
-include("ns_common.hrl").
+-include("ns_config.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -225,10 +226,22 @@ do_upgrade_config_from_1_6_to_1_7(Config, DefaultConfig) ->
lists:keyreplace(element(1, T), 1, Acc, T)
end, MemcachedCfg, [BucketEnCfg,
EnginesCfg]),
- [{set, {node, node(), memcached}, NewMemcachedCfg}] ++
+
+ VClock = vclock:increment(node(), vclock:fresh()),
+ AddVClock = fun (Value) ->
+ [{?METADATA_VCLOCK, VClock} | Value]
+ end,
+
+ [{set, {node, node(), memcached}, AddVClock(NewMemcachedCfg)}] ++
lists:foldl(fun (K, Acc) ->
{K,V} = lists:keyfind(K, 1, DefaultConfig),
- [{set, K, V} | Acc]
+ V1 = case K of
+ {node, Node, _K} when node() =:= Node ->
+ AddVClock(V);
+ _Otherwise ->
+ V
+ end,
+ [{set, K, V1} | Acc]
end, [],
[directory,
{node, node(), isasl},
@@ -261,9 +274,27 @@ upgrade_1_6_to_1_7_test() ->
[{dbdir, "dbdir"},
{bucket_engine, "old-be"},
{engines, "old-engines"}]}],
+
+ StripValue = fun ([{?METADATA_VCLOCK, _V} | Rest]) ->
+ Rest;
+ (Other) ->
+ Other
+ end,
+ Strip = fun (Config) ->
+ lists:map(
+ fun ({set, K, V}) ->
+ {set, K, StripValue(V)};
+ (Other) ->
+ Other
+ end,
+ Config)
+ end,
+
Res = do_upgrade_config_from_1_6_to_1_7([OldCfg], DefaultCfg),
+
?assertEqual(lists:sort([{set, directory, default_directory},
- {set, {node, node(), isasl}, [{path, default_isasl}]},
+ {set, {node, node(), isasl},
+ [{path, default_isasl}]},
{set, {node, node(), memcached},
[{dbdir, "dbdir"},
{bucket_engine, "new-be"},
@@ -272,7 +303,7 @@ upgrade_1_6_to_1_7_test() ->
[{moxi, "moxi something"},
{memcached, "memcached something"}]},
{set, {node, node(), ns_log}, default_log}]),
- lists:sort(Res)).
+ lists:sort(Strip(Res))).
no_upgrade_on_1_7_1_test() ->
?assertEqual([], upgrade_config([[{{node, node(), config_version}, {1,7,1}}]])).
@@ -309,5 +340,15 @@ fuller_1_6_test_() ->
[X || {set, directory, _} = X <- Changes]),
{set, _, NewMemcached} = lists:keyfind({node, node(), memcached}, 2, Changes),
- ?assertEqual({dbdir, "dbdir"}, lists:keyfind(dbdir, 1, NewMemcached))
+ ?assertEqual({dbdir, "dbdir"}, lists:keyfind(dbdir, 1, NewMemcached)),
+
+ ?assertMatch({set, {node, Node, memcached},
+ [{?METADATA_VCLOCK, _VClock} | _]} when Node =:= node(),
+ lists:keyfind({node, node(), memcached}, 2, Changes)),
+ ?assertMatch({set, {node, Node, isasl},
+ [{?METADATA_VCLOCK, _VClock} | _]} when Node =:= node(),
+ lists:keyfind({node, node(), isasl}, 2, Changes)),
+ ?assertMatch({set, {node, Node, ns_log},
+ [{?METADATA_VCLOCK, _VClock} | _]} when Node =:= node(),
+ lists:keyfind({node, node(), ns_log}, 2, Changes))
end}.

0 comments on commit 8500032

Please sign in to comment.