Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
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...
commit 850003232fb2bc2ec1a7cc8862419a28cda4b456 1 parent 02ef5f3
@aartamonau aartamonau authored alk committed
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}.
Please sign in to comment.
Something went wrong with that request. Please try again.