From 2951ba35de1fc7213121a9b45b7ff679d543c5d3 Mon Sep 17 00:00:00 2001 From: Kai Lautaportti Date: Thu, 28 Nov 2013 14:26:46 +0200 Subject: [PATCH 1/2] Use CL.ONE explicitly when interacting with the system keyspace The system keyspace uses "LocalStrategy" for replication so it needs to be accessed with CL.ONE. If the default consistency level is set to something else all management commands which rely on introspecting the system keyspace will fail. --- cqlengine/management.py | 16 ++++++++++------ .../tests/connections/test_connection_pool.py | 3 ++- cqlengine/tests/management/test_management.py | 3 ++- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/cqlengine/management.py b/cqlengine/management.py index 81771c48..b7cdf4d1 100644 --- a/cqlengine/management.py +++ b/cqlengine/management.py @@ -1,6 +1,7 @@ import json import warnings from cqlengine import SizeTieredCompactionStrategy, LeveledCompactionStrategy +from cqlengine import ONE from cqlengine.named import NamedTable from cqlengine.connection import connection_manager, execute @@ -28,7 +29,7 @@ def create_keyspace(name, strategy_class='SimpleStrategy', replication_factor=3, :param **replication_values: 1.2 only, additional values to ad to the replication data map """ with connection_manager() as con: - _, keyspaces = con.execute("""SELECT keyspace_name FROM system.schema_keyspaces""", {}) + _, keyspaces = con.execute("""SELECT keyspace_name FROM system.schema_keyspaces""", {}, ONE) if name not in [r[0] for r in keyspaces]: #try the 1.2 method replication_map = { @@ -55,7 +56,7 @@ def create_keyspace(name, strategy_class='SimpleStrategy', replication_factor=3, def delete_keyspace(name): with connection_manager() as con: - _, keyspaces = con.execute("""SELECT keyspace_name FROM system.schema_keyspaces""", {}) + _, keyspaces = con.execute("""SELECT keyspace_name FROM system.schema_keyspaces""", {}, ONE) if name in [r[0] for r in keyspaces]: execute("DROP KEYSPACE {}".format(name)) @@ -80,7 +81,8 @@ def sync_table(model, create_missing_keyspace=True): with connection_manager() as con: tables = con.execute( "SELECT columnfamily_name from system.schema_columnfamilies WHERE keyspace_name = :ks_name", - {'ks_name': ks_name} + {'ks_name': ks_name}, + ONE ) tables = [x[0] for x in tables.results] @@ -115,7 +117,8 @@ def sync_table(model, create_missing_keyspace=True): with connection_manager() as con: _, idx_names = con.execute( "SELECT index_name from system.\"IndexInfo\" WHERE table_name=:table_name", - {'table_name': raw_cf_name} + {'table_name': raw_cf_name}, + ONE ) idx_names = [i[0] for i in idx_names] @@ -230,7 +233,7 @@ def get_fields(model): logger.debug("get_fields %s %s", ks_name, col_family) - tmp = con.execute(query, {'ks_name':ks_name, 'col_family':col_family}) + tmp = con.execute(query, {'ks_name': ks_name, 'col_family': col_family}, ONE) return [Field(x[0], x[1]) for x in tmp.results] # convert to Field named tuples @@ -282,7 +285,8 @@ def drop_table(model): with connection_manager() as con: _, tables = con.execute( "SELECT columnfamily_name from system.schema_columnfamilies WHERE keyspace_name = :ks_name", - {'ks_name': ks_name} + {'ks_name': ks_name}, + ONE ) raw_cf_name = model.column_family_name(include_keyspace=False) if raw_cf_name not in [t[0] for t in tables]: diff --git a/cqlengine/tests/connections/test_connection_pool.py b/cqlengine/tests/connections/test_connection_pool.py index 29b3ea50..b34ea471 100644 --- a/cqlengine/tests/connections/test_connection_pool.py +++ b/cqlengine/tests/connections/test_connection_pool.py @@ -2,6 +2,7 @@ from unittest import TestCase from cql import OperationalError from mock import MagicMock, patch, Mock +from cqlengine import ONE from cqlengine.connection import ConnectionPool, Host @@ -18,4 +19,4 @@ class OperationalErrorLoggingTest(TestCase): with patch.object(p, 'get', return_value=MockConnection()): with self.assertRaises(OperationalError): - p.execute("select * from system.peers", {}) + p.execute("select * from system.peers", {}, ONE) diff --git a/cqlengine/tests/management/test_management.py b/cqlengine/tests/management/test_management.py index 88405b1e..25f4d268 100644 --- a/cqlengine/tests/management/test_management.py +++ b/cqlengine/tests/management/test_management.py @@ -1,5 +1,6 @@ from mock import MagicMock, patch +from cqlengine import ONE from cqlengine.exceptions import CQLEngineException from cqlengine.management import create_table, delete_table, get_fields from cqlengine.tests.base import BaseCassEngTestCase @@ -22,7 +23,7 @@ class ConnectionPoolFailoverTestCase(BaseCassEngTestCase): with patch('cqlengine.connection.cql.connect') as mock: mock.side_effect=CQLEngineException with self.assertRaises(CQLEngineException): - self.pool.execute("select * from system.peers", {}) + self.pool.execute("select * from system.peers", {}, ONE) def test_dead_node(self): """ From 380eeeb8cabce3cd817ffa775d58c596b0e53c81 Mon Sep 17 00:00:00 2001 From: Kai Lautaportti Date: Tue, 10 Dec 2013 11:57:24 +0200 Subject: [PATCH 2/2] Make get_table_settings use CL.ONE explicitly --- cqlengine/management.py | 5 +++-- cqlengine/query.py | 10 +++++----- setup.py | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/cqlengine/management.py b/cqlengine/management.py index b7cdf4d1..6d41489e 100644 --- a/cqlengine/management.py +++ b/cqlengine/management.py @@ -239,8 +239,9 @@ def get_fields(model): def get_table_settings(model): - return schema_columnfamilies.get(keyspace_name=model._get_keyspace(), - columnfamily_name=model.column_family_name(include_keyspace=False)) + return schema_columnfamilies.objects.consistency(ONE).get( + keyspace_name=model._get_keyspace(), + columnfamily_name=model.column_family_name(include_keyspace=False)) def update_compaction(model): diff --git a/cqlengine/query.py b/cqlengine/query.py index 1b9ea244..ed59e077 100644 --- a/cqlengine/query.py +++ b/cqlengine/query.py @@ -318,6 +318,11 @@ class AbstractQuerySet(object): def all(self): return copy.deepcopy(self) + def consistency(self, consistency): + clone = copy.deepcopy(self) + clone._consistency = consistency + return clone + def _parse_filter_arg(self, arg): """ Parses a filter arg in the format: @@ -626,11 +631,6 @@ class ModelQuerySet(AbstractQuerySet): clone._flat_values_list = flat return clone - def consistency(self, consistency): - clone = copy.deepcopy(self) - clone._consistency = consistency - return clone - def ttl(self, ttl): clone = copy.deepcopy(self) clone._ttl = ttl diff --git a/setup.py b/setup.py index 2965a6d7..98700ad6 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ Cassandra CQL 3 Object Mapper for Python setup( name='cqlengine', - version=version, + version='0.9.2-2951ba35de1fc7213121a9b45b7ff679d543c5d3', description='Cassandra CQL 3 Object Mapper for Python', long_description=long_desc, classifiers = [