Merge pull request #284 from datastax/PYTHON-241

PYTHON-241 - Meta indexes for Index Meta
This commit is contained in:
Adam Holmberg
2015-04-22 14:02:31 -05:00
2 changed files with 134 additions and 9 deletions

View File

@@ -122,10 +122,8 @@ class Metadata(object):
keyspace_col_rows = col_def_rows.get(keyspace_meta.name, {}) keyspace_col_rows = col_def_rows.get(keyspace_meta.name, {})
keyspace_trigger_rows = trigger_rows.get(keyspace_meta.name, {}) keyspace_trigger_rows = trigger_rows.get(keyspace_meta.name, {})
for table_row in cf_def_rows.get(keyspace_meta.name, []): for table_row in cf_def_rows.get(keyspace_meta.name, []):
table_meta = self._build_table_metadata( table_meta = self._build_table_metadata(keyspace_meta, table_row, keyspace_col_rows, keyspace_trigger_rows)
keyspace_meta, table_row, keyspace_col_rows, keyspace_meta._add_table_metadata(table_meta)
keyspace_trigger_rows)
keyspace_meta.tables[table_meta.name] = table_meta
for usertype_row in usertype_rows.get(keyspace_meta.name, []): for usertype_row in usertype_rows.get(keyspace_meta.name, []):
usertype = self._build_usertype(keyspace_meta.name, usertype_row) usertype = self._build_usertype(keyspace_meta.name, usertype_row)
@@ -160,6 +158,7 @@ class Metadata(object):
if old_keyspace_meta: if old_keyspace_meta:
keyspace_meta.tables = old_keyspace_meta.tables keyspace_meta.tables = old_keyspace_meta.tables
keyspace_meta.user_types = old_keyspace_meta.user_types keyspace_meta.user_types = old_keyspace_meta.user_types
keyspace_meta.indexes = old_keyspace_meta.indexes
if (keyspace_meta.replication_strategy != old_keyspace_meta.replication_strategy): if (keyspace_meta.replication_strategy != old_keyspace_meta.replication_strategy):
self._keyspace_updated(keyspace) self._keyspace_updated(keyspace)
else: else:
@@ -184,12 +183,11 @@ class Metadata(object):
if not cf_results: if not cf_results:
# the table was removed # the table was removed
keyspace_meta.tables.pop(table, None) keyspace_meta._drop_table_metadata(table)
else: else:
assert len(cf_results) == 1 assert len(cf_results) == 1
keyspace_meta.tables[table] = self._build_table_metadata( table_meta = self._build_table_metadata(keyspace_meta, cf_results[0], {table: col_results}, {table: triggers_result})
keyspace_meta, cf_results[0], {table: col_results}, keyspace_meta._add_table_metadata(table_meta)
{table: triggers_result})
def _keyspace_added(self, ksname): def _keyspace_added(self, ksname):
if self.token_map: if self.token_map:
@@ -385,6 +383,8 @@ class Metadata(object):
column_meta = ColumnMetadata(table_metadata, name, data_type, is_static=is_static) column_meta = ColumnMetadata(table_metadata, name, data_type, is_static=is_static)
index_meta = self._build_index_metadata(column_meta, row) index_meta = self._build_index_metadata(column_meta, row)
column_meta.index = index_meta column_meta.index = index_meta
if index_meta:
table_metadata.indexes[index_meta.name] = index_meta
return column_meta return column_meta
def _build_index_metadata(self, column_metadata, row): def _build_index_metadata(self, column_metadata, row):
@@ -733,6 +733,11 @@ class KeyspaceMetadata(object):
A map from table names to instances of :class:`~.TableMetadata`. A map from table names to instances of :class:`~.TableMetadata`.
""" """
indexes = None
"""
A dict mapping index names to :class:`.IndexMetadata` instances.
"""
user_types = None user_types = None
""" """
A map from user-defined type names to instances of :class:`~cassandra.metadata..UserType`. A map from user-defined type names to instances of :class:`~cassandra.metadata..UserType`.
@@ -745,6 +750,7 @@ class KeyspaceMetadata(object):
self.durable_writes = durable_writes self.durable_writes = durable_writes
self.replication_strategy = ReplicationStrategy.create(strategy_class, strategy_options) self.replication_strategy = ReplicationStrategy.create(strategy_class, strategy_options)
self.tables = {} self.tables = {}
self.indexes = {}
self.user_types = {} self.user_types = {}
def export_as_string(self): def export_as_string(self):
@@ -780,6 +786,18 @@ class KeyspaceMetadata(object):
self.resolve_user_types(field_type.typename, types, user_type_strings) self.resolve_user_types(field_type.typename, types, user_type_strings)
user_type_strings.append(user_type.as_cql_query(formatted=True)) user_type_strings.append(user_type.as_cql_query(formatted=True))
def _add_table_metadata(self, table_metadata):
self._drop_table_metadata(table_metadata.name)
self.tables[table_metadata.name] = table_metadata
for index_name, index_metadata in six.iteritems(table_metadata.indexes):
self.indexes[index_name] = index_metadata
def _drop_table_metadata(self, table_name):
table_meta = self.tables.pop(table_name, None)
if table_meta:
for index_name in table_meta.indexes:
self.indexes.pop(index_name, None)
class UserType(object): class UserType(object):
""" """
@@ -884,6 +902,11 @@ class TableMetadata(object):
A dict mapping column names to :class:`.ColumnMetadata` instances. A dict mapping column names to :class:`.ColumnMetadata` instances.
""" """
indexes = None
"""
A dict mapping index names to :class:`.IndexMetadata` instances.
"""
is_compact_storage = False is_compact_storage = False
options = None options = None
@@ -945,6 +968,7 @@ class TableMetadata(object):
self.partition_key = [] if partition_key is None else partition_key self.partition_key = [] if partition_key is None else partition_key
self.clustering_key = [] if clustering_key is None else clustering_key self.clustering_key = [] if clustering_key is None else clustering_key
self.columns = OrderedDict() if columns is None else columns self.columns = OrderedDict() if columns is None else columns
self.indexes = {}
self.options = options self.options = options
self.comparator = None self.comparator = None
self.triggers = OrderedDict() if triggers is None else triggers self.triggers = OrderedDict() if triggers is None else triggers
@@ -1242,6 +1266,12 @@ class IndexMetadata(object):
protect_name(self.column.name), protect_name(self.column.name),
self.index_options["class_name"]) self.index_options["class_name"])
def export_as_string(self):
"""
Returns a CQL query string that can be used to recreate this index.
"""
return self.as_cql_query() + ';'
class TokenMap(object): class TokenMap(object):
""" """

View File

@@ -25,7 +25,7 @@ import sys
from cassandra import AlreadyExists from cassandra import AlreadyExists
from cassandra.cluster import Cluster from cassandra.cluster import Cluster
from cassandra.metadata import (Metadata, KeyspaceMetadata, TableMetadata, from cassandra.metadata import (Metadata, KeyspaceMetadata, TableMetadata, IndexMetadata,
Token, MD5Token, TokenMap, murmur3) Token, MD5Token, TokenMap, murmur3)
from cassandra.policies import SimpleConvictionPolicy from cassandra.policies import SimpleConvictionPolicy
from cassandra.pool import Host from cassandra.pool import Host
@@ -900,3 +900,98 @@ class KeyspaceAlterMetadata(unittest.TestCase):
new_keyspace_meta = self.cluster.metadata.keyspaces[name] new_keyspace_meta = self.cluster.metadata.keyspaces[name]
self.assertNotEqual(original_keyspace_meta, new_keyspace_meta) self.assertNotEqual(original_keyspace_meta, new_keyspace_meta)
self.assertEqual(new_keyspace_meta.durable_writes, False) self.assertEqual(new_keyspace_meta.durable_writes, False)
class IndexMapTests(unittest.TestCase):
keyspace_name = 'index_map_tests'
@property
def table_name(self):
return self._testMethodName.lower()
@classmethod
def setup_class(cls):
cls.cluster = Cluster(protocol_version=PROTOCOL_VERSION)
cls.session = cls.cluster.connect()
try:
if cls.keyspace_name in cls.cluster.metadata.keyspaces:
cls.session.execute("DROP KEYSPACE %s" % cls.keyspace_name)
cls.session.execute(
"""
CREATE KEYSPACE %s
WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'};
""" % cls.keyspace_name)
cls.session.set_keyspace(cls.keyspace_name)
except Exception:
cls.cluster.shutdown()
raise
@classmethod
def teardown_class(cls):
try:
cls.session.execute("DROP KEYSPACE %s" % cls.keyspace_name)
finally:
cls.cluster.shutdown()
def create_basic_table(self):
self.session.execute("CREATE TABLE %s (k int PRIMARY KEY, a int)" % self.table_name)
def drop_basic_table(self):
self.session.execute("DROP TABLE %s" % self.table_name)
def test_index_updates(self):
self.create_basic_table()
ks_meta = self.cluster.metadata.keyspaces[self.keyspace_name]
table_meta = ks_meta.tables[self.table_name]
self.assertNotIn('a_idx', ks_meta.indexes)
self.assertNotIn('b_idx', ks_meta.indexes)
self.assertNotIn('a_idx', table_meta.indexes)
self.assertNotIn('b_idx', table_meta.indexes)
self.session.execute("CREATE INDEX a_idx ON %s (a)" % self.table_name)
self.session.execute("ALTER TABLE %s ADD b int" % self.table_name)
self.session.execute("CREATE INDEX b_idx ON %s (b)" % self.table_name)
ks_meta = self.cluster.metadata.keyspaces[self.keyspace_name]
table_meta = ks_meta.tables[self.table_name]
self.assertIsInstance(ks_meta.indexes['a_idx'], IndexMetadata)
self.assertIsInstance(ks_meta.indexes['b_idx'], IndexMetadata)
self.assertIsInstance(table_meta.indexes['a_idx'], IndexMetadata)
self.assertIsInstance(table_meta.indexes['b_idx'], IndexMetadata)
# both indexes updated when index dropped
self.session.execute("DROP INDEX a_idx")
ks_meta = self.cluster.metadata.keyspaces[self.keyspace_name]
table_meta = ks_meta.tables[self.table_name]
self.assertNotIn('a_idx', ks_meta.indexes)
self.assertIsInstance(ks_meta.indexes['b_idx'], IndexMetadata)
self.assertNotIn('a_idx', table_meta.indexes)
self.assertIsInstance(table_meta.indexes['b_idx'], IndexMetadata)
# keyspace index updated when table dropped
self.drop_basic_table()
ks_meta = self.cluster.metadata.keyspaces[self.keyspace_name]
self.assertNotIn(self.table_name, ks_meta.tables)
self.assertNotIn('a_idx', ks_meta.indexes)
self.assertNotIn('b_idx', ks_meta.indexes)
def test_index_follows_alter(self):
self.create_basic_table()
idx = self.table_name + '_idx'
self.session.execute("CREATE INDEX %s ON %s (a)" % (idx, self.table_name))
ks_meta = self.cluster.metadata.keyspaces[self.keyspace_name]
table_meta = ks_meta.tables[self.table_name]
self.assertIsInstance(ks_meta.indexes[idx], IndexMetadata)
self.assertIsInstance(table_meta.indexes[idx], IndexMetadata)
self.session.execute('ALTER KEYSPACE %s WITH durable_writes = false' % self.keyspace_name)
old_meta = ks_meta
ks_meta = self.cluster.metadata.keyspaces[self.keyspace_name]
self.assertIsNot(ks_meta, old_meta)
table_meta = ks_meta.tables[self.table_name]
self.assertIsInstance(ks_meta.indexes[idx], IndexMetadata)
self.assertIsInstance(table_meta.indexes[idx], IndexMetadata)
self.drop_basic_table()