Skip to content

Commit ac676b1

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 ac676b1

File tree

1 file changed

+121
-0
lines changed

1 file changed

+121
-0
lines changed

system_keyspaces_test.py

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

0 commit comments

Comments
 (0)