Skip to content

Commit 7f6670d

Browse files
Add tests for host_id consistency
patch by Jacek Lewandowski; reviewed by Stefan Miklosovic and Sam Tunnicliffe for CASSANDRA-18153
1 parent 5fd2c34 commit 7f6670d

File tree

1 file changed

+122
-0
lines changed

1 file changed

+122
-0
lines changed

system_keyspaces_test.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import pytest
22
import logging
3+
import re
4+
import time
35

46
from cassandra import Unauthorized
57
from dtest import Tester
@@ -12,6 +14,126 @@
1214

1315
class TestSystemKeyspaces(Tester):
1416

17+
@since('3.0')
18+
def test_host_id_is_set(self):
19+
"""
20+
@jira_ticket CASSANDRA-18153
21+
22+
Test that the host ID in system.local is set after startup.
23+
"""
24+
cluster = self.cluster
25+
cluster.data_dir_count = 1
26+
cluster.set_configuration_options(values={'commitlog_sync_period_in_ms': 500})
27+
cluster.populate(1).start()
28+
node = cluster.nodelist()[0]
29+
node.nodetool("disableautocompaction")
30+
31+
session = self.patient_cql_connection(node)
32+
host_id_in_system_local = str(session.execute("SELECT host_id FROM system.local")[0].host_id)
33+
34+
session.execute("CREATE KEYSPACE ks WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}")
35+
session.execute("CREATE TABLE ks.cf (k int PRIMARY KEY, v int)")
36+
node.nodetool("disableautocompaction ks cf")
37+
38+
session.execute("INSERT INTO ks.cf (k, v) VALUES (0, 0)")
39+
node.flush()
40+
41+
self.assert_host_id_in_all_sstables(host_id_in_system_local, node)
42+
43+
# let's have something in the commitlog which was not flushed to sstable
44+
session.execute("INSERT INTO ks.cf (k, v) VALUES (1, 1)")
45+
46+
# wait for the commitlog to be synced and kill the node
47+
time.sleep(2)
48+
cluster.stop(gently=False)
49+
50+
cluster.start(wait_for_binary_proto=True)
51+
session = self.patient_cql_connection(node)
52+
assert host_id_in_system_local == str(session.execute("SELECT host_id FROM system.local")[0].host_id), "Host ID in system.local changed after restart"
53+
54+
node.flush()
55+
self.assert_host_id_in_all_sstables(host_id_in_system_local, node)
56+
57+
@since('3.0')
58+
def test_consistent_host_id(self):
59+
"""
60+
@jira_ticket CASSANDRA-18153
61+
62+
Test that the host ID in system.local is consistent across restarts.
63+
"""
64+
cluster = self.cluster
65+
cluster.set_configuration_options(values={'commitlog_sync_period_in_ms': 500})
66+
cluster.populate(1).start()
67+
node = cluster.nodelist()[0]
68+
69+
session = self.patient_cql_connection(node)
70+
host_id_in_system_local = str(session.execute("SELECT host_id FROM system.local")[0].host_id)
71+
logger.info("Host ID in system.local: {}".format(host_id_in_system_local))
72+
73+
session.execute("CREATE KEYSPACE ks WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}")
74+
session.execute("CREATE TABLE ks.cf (k int PRIMARY KEY, v int)")
75+
76+
session.execute("INSERT INTO ks.cf (k, v) VALUES (0, 0)")
77+
node.flush()
78+
79+
# let's do something nasty - system.local is flushed without host ID
80+
session.execute("UPDATE system.local SET host_id = NULL WHERE key = 'local'")
81+
node.flush()
82+
node.compact()
83+
84+
# let's generate some random host ID and leave it only in the commitlog
85+
random_host_id = "12345678-1234-1234-1234-123456789012"
86+
session.execute("UPDATE system.local SET host_id = {} WHERE key = 'local'".format(random_host_id))
87+
88+
# wait for the commitlog to be synced and kill the node
89+
time.sleep(2)
90+
cluster.stop(gently=False)
91+
92+
cluster.start(wait_for_binary_proto=True)
93+
session = self.patient_cql_connection(node)
94+
95+
host_id_in_system_local_after_restart = str(session.execute("SELECT host_id FROM system.local")[0].host_id)
96+
logger.info("Host ID in system.local after restart: {}".format(host_id_in_system_local_after_restart))
97+
# now we expect that although system.local has no host ID, it wasn't generated at startup because there was something in the commitlog
98+
# eventually, we should read that new host ID from the commitlog
99+
assert host_id_in_system_local_after_restart == random_host_id, "Host ID in system.local changed after restart: {} != {}".format(host_id_in_system_local_after_restart, random_host_id)
100+
101+
def get_host_id_from_sstable_metadata(self, node, sstable_paths):
102+
host_ids = {}
103+
for sstable_path in sstable_paths:
104+
(out, err, rc) = node.run_sstablemetadata(datafiles=[sstable_path])
105+
assert rc == 0, "sstablemetadata failed with error: {}".format(err)
106+
# extract host id from out using "Originating host id: (\\S*)" regex
107+
host_id = re.search("Originating host id: (\\S*)", out)
108+
if host_id is None:
109+
logger.info("Could not find host ID in sstablemetadata output: {}".format(out))
110+
else:
111+
if sstable_path in host_ids:
112+
logger.info("Duplicate sstable path: {}".format(sstable_path))
113+
host_ids[sstable_path] = host_id.group(1)
114+
115+
return host_ids
116+
117+
def assert_host_id_in_all_sstables(self, expected_host_id, node):
118+
keyspaces = node.list_keyspaces()
119+
# we need to explicitly add local system keyspace to the list
120+
keyspaces.append("system")
121+
122+
sstable_paths = []
123+
for keyspace in keyspaces:
124+
sstable_paths.extend(node.get_sstables(keyspace, ""))
125+
126+
host_ids = self.get_host_id_from_sstable_metadata(node, sstable_paths)
127+
assert len(host_ids) == len(sstable_paths), "Expected to find host ID in all sstables: {} != {}".format(
128+
len(host_ids), len(sstable_paths))
129+
130+
# assert that host IDs in system.local and sstables are the same
131+
for sstable_path in sstable_paths:
132+
assert expected_host_id == host_ids[sstable_path], \
133+
"Host ID in system.local and sstable {} are different: {} != {}".format(sstable_path,
134+
expected_host_id,
135+
host_ids[sstable_path])
136+
15137
@since('3.0')
16138
def test_local_system_keyspaces(self):
17139
cluster = self.cluster

0 commit comments

Comments
 (0)