Skip to content

Commit 48830cf

Browse files
committed
Merge remote-tracking branch 'couchbase/trinity' into phoenix
* MB-68048: Fix no-op evictionPolicy updates during storage mode migration Change-Id: Iefb9ab0362a425a172911da0ad7a264859f0a51a
2 parents e9d53e3 + b8f7948 commit 48830cf

File tree

2 files changed

+108
-1
lines changed

2 files changed

+108
-1
lines changed

apps/ns_server/src/ns_bucket.erl

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2073,7 +2073,30 @@ maybe_update_eviction_policy_overrides(NewProps, BucketConfig,
20732073
{NewProps, ExistingDeleteKeys}
20742074
end;
20752075
false ->
2076-
case proplists:get_value(eviction_policy, NewProps) =/= undefined of
2076+
%% Why not use eviction_policy_changed/2 here?
2077+
%% Mixed eviction policy changes:
2078+
%% When a user mixes eviction policy changes that require a restart
2079+
%% with those that don’t, we delete eviction policy overrides (if
2080+
%% --noRestart is omitted) and reset to a clean slate. The new
2081+
%% eviction policy takes effect immediately.
2082+
%%
2083+
%% Exception during storage mode migration:
2084+
%% During a storage mode migration, the only eviction policy changes
2085+
%% allowed are those with --noRestart.
2086+
%% The REST API ignores attempts to modify bucket-level properties
2087+
%% that can’t be changed during migration if the value stays the
2088+
%% same. If the value changes, it throws an error indicating storage
2089+
%% migration is in progress.
2090+
%%
2091+
%% Behavior we retain:
2092+
%% If the user sets the eviction policy to the same value it already
2093+
%% has, we don’t delete overrides or trigger a restart. Any existing
2094+
%% overrides remain until a swap rebalance or graceful failover and
2095+
%% full recovery.
2096+
PolicySpecified =
2097+
proplists:get_value(eviction_policy, NewProps) =/= undefined,
2098+
case PolicySpecified andalso not
2099+
storage_mode_migration_in_progress(BucketConfig) of
20772100
true ->
20782101
%% By default, eviction policy changes force a bucket
20792102
%% restart. Delete any existing eviction policy overrides.

cluster_tests/testsets/bucket_migration_test.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,3 +1049,87 @@ def check_eviction_policy_changed():
10491049
)
10501050

10511051
self.cluster.delete_bucket(bucket_name)
1052+
1053+
def eviction_policy_noop_no_restart_storage_mode_migration_test(
1054+
self,
1055+
):
1056+
"""
1057+
Start a storage mode migration with an eviction policy change using
1058+
--noRestart.
1059+
Then send an evictionPolicy update without --noRestart but with the
1060+
identical bucket-level eviction policy value, and verify it's treated as
1061+
a no-op:
1062+
- No per-node eviction overrides disappear
1063+
- No per-node storage mode overrides disappear
1064+
"""
1065+
bucket_name = "bucket-evict-noop-test"
1066+
1067+
# Create couchstore + valueOnly
1068+
create_bucket(
1069+
self.cluster, bucket_name, "couchstore", 1024, "valueOnly"
1070+
)
1071+
1072+
# Begin migration to magma and change eviction policy with --noRestart
1073+
# This should add per-node storage_mode=couchstore and
1074+
# eviction_policy=valueOnly overrides
1075+
update_data = {
1076+
"name": bucket_name,
1077+
"storageBackend": "magma",
1078+
"evictionPolicy": "fullEviction",
1079+
"noRestart": "true",
1080+
}
1081+
self.cluster.update_bucket(update_data)
1082+
1083+
# Capture overrides before the no-op request
1084+
per_node_storage_mode_before = get_per_node_storage_mode(
1085+
self.cluster, bucket_name
1086+
)
1087+
per_node_eviction_policy_before = get_per_node_eviction_policy(
1088+
self.cluster, bucket_name
1089+
)
1090+
1091+
# Sanity: overrides were created as expected
1092+
assert_per_node_storage_mode_keys_added(
1093+
self.cluster, bucket_name, "couchstore"
1094+
)
1095+
assert_per_node_eviction_policy_keys_added(
1096+
self.cluster, bucket_name, "valueOnly"
1097+
)
1098+
1099+
# Now send evictionPolicy again without noRestart but with identical
1100+
# value ("fullEviction"). This should be a no-op and must not delete the
1101+
# per-node eviction overrides
1102+
noop_update = {
1103+
"name": bucket_name,
1104+
"evictionPolicy": "fullEviction",
1105+
# noRestart intentionally omitted
1106+
}
1107+
self.cluster.update_bucket(noop_update)
1108+
1109+
# Verify overrides did not disappear
1110+
per_node_storage_mode_after = get_per_node_storage_mode(
1111+
self.cluster, bucket_name
1112+
)
1113+
per_node_eviction_policy_after = get_per_node_eviction_policy(
1114+
self.cluster, bucket_name
1115+
)
1116+
1117+
assert (
1118+
per_node_storage_mode_after == per_node_storage_mode_before
1119+
), f"per-node storage mode overrides changed on no-op: "
1120+
f"{per_node_storage_mode_before} -> {per_node_storage_mode_after}"
1121+
1122+
assert (
1123+
per_node_eviction_policy_after == per_node_eviction_policy_before
1124+
), f"per-node eviction overrides changed on no-op: "
1125+
f"{per_node_eviction_policy_before} -> {per_node_eviction_policy_after}"
1126+
1127+
# And that they are still the expected values
1128+
assert_per_node_storage_mode_keys_added(
1129+
self.cluster, bucket_name, "couchstore"
1130+
)
1131+
assert_per_node_eviction_policy_keys_added(
1132+
self.cluster, bucket_name, "valueOnly"
1133+
)
1134+
1135+
self.cluster.delete_bucket(bucket_name)

0 commit comments

Comments
 (0)