blob: 8ff482271ea873547cc262e9260ebaca507be7a4 [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
try:
from Queue import Queue, Empty
except ImportError:
from queue import Queue, Empty # noqa
from struct import pack
import logging, sys, traceback, time
from cassandra import ConsistencyLevel, OperationTimedOut, WriteTimeout
from cassandra.cluster import ExecutionProfile, EXEC_PROFILE_DEFAULT
from cassandra.query import dict_factory
from cassandra.query import SimpleStatement
from tests.integration import use_singledc, PROTOCOL_VERSION, TestCluster
from tests.integration.long.utils import create_schema
import unittest
log = logging.getLogger(__name__)
def setup_module():
use_singledc()
# Converts an integer to an string of letters
def create_column_name(i):
letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
column_name = ''
while True:
column_name += letters[i % 10]
i = i // 10
if not i:
break
if column_name == 'if':
column_name = 'special_case'
return column_name
class LargeDataTests(unittest.TestCase):
def setUp(self):
self.keyspace = 'large_data'
def make_session_and_keyspace(self):
cluster = TestCluster(execution_profiles={
EXEC_PROFILE_DEFAULT: ExecutionProfile(request_timeout=20, row_factory=dict_factory)
})
session = cluster.connect()
create_schema(cluster, session, self.keyspace)
return session
def batch_futures(self, session, statement_generator):
concurrency = 10
futures = Queue(maxsize=concurrency)
number_of_timeouts = 0
for i, statement in enumerate(statement_generator):
if i > 0 and i % (concurrency - 1) == 0:
# clear the existing queue
while True:
try:
futures.get_nowait().result()
except (OperationTimedOut, WriteTimeout):
ex_type, ex, tb = sys.exc_info()
number_of_timeouts += 1
log.warning("{0}: {1} Backtrace: {2}".format(ex_type.__name__, ex, traceback.extract_tb(tb)))
del tb
time.sleep(1)
except Empty:
break
future = session.execute_async(statement)
futures.put_nowait(future)
while True:
try:
futures.get_nowait().result()
except (OperationTimedOut, WriteTimeout):
ex_type, ex, tb = sys.exc_info()
number_of_timeouts += 1
log.warning("{0}: {1} Backtrace: {2}".format(ex_type.__name__, ex, traceback.extract_tb(tb)))
del tb
time.sleep(1)
except Empty:
break
return number_of_timeouts
def test_wide_rows(self):
table = 'wide_rows'
session = self.make_session_and_keyspace()
session.execute('CREATE TABLE %s (k INT, i INT, PRIMARY KEY(k, i))' % table)
prepared = session.prepare('INSERT INTO %s (k, i) VALUES (0, ?)' % (table, ))
# Write via async futures
self.batch_futures(session, (prepared.bind((i, )) for i in range(100000)))
# Read
results = session.execute('SELECT i FROM %s WHERE k=0' % (table, ))
# Verify
for i, row in enumerate(results):
self.assertAlmostEqual(row['i'], i, delta=3)
session.cluster.shutdown()
def test_wide_batch_rows(self):
"""
Test for inserting wide rows with batching
test_wide_batch_rows tests inserting a wide row of data using batching. It will then attempt to query
that data and ensure that all of it has been inserted appropriately.
@expected_result all items should be inserted, and verified.
@test_category queries:batch
"""
# Table Creation
table = 'wide_batch_rows'
session = self.make_session_and_keyspace()
session.execute('CREATE TABLE %s (k INT, i INT, PRIMARY KEY(k, i))' % table)
# Run batch insert
statement = 'BEGIN BATCH '
to_insert = 2000
for i in range(to_insert):
statement += 'INSERT INTO %s (k, i) VALUES (%s, %s) ' % (table, 0, i)
statement += 'APPLY BATCH'
statement = SimpleStatement(statement, consistency_level=ConsistencyLevel.QUORUM)
# Execute insert with larger timeout, since it's a wide row
try:
session.execute(statement,timeout=30.0)
except OperationTimedOut:
#If we timeout on insertion that's bad but it could be just slow underlying c*
#Attempt to validate anyway, we will fail if we don't get the right data back.
ex_type, ex, tb = sys.exc_info()
log.warning("Batch wide row insertion timed out, this may require additional investigation")
log.warning("{0}: {1} Backtrace: {2}".format(ex_type.__name__, ex, traceback.extract_tb(tb)))
del tb
# Verify
results = session.execute('SELECT i FROM %s WHERE k=%s' % (table, 0))
lastvalue = 0
for j, row in enumerate(results):
lastValue=row['i']
self.assertEqual(lastValue, j)
#check the last value make sure it's what we expect
index_value = to_insert-1
self.assertEqual(lastValue,index_value,"Verification failed only found {0} inserted we were expecting {1}".format(j,index_value))
session.cluster.shutdown()
def test_wide_byte_rows(self):
"""
Test for inserting wide row of bytes
test_wide_batch_rows tests inserting a wide row of data bytes. It will then attempt to query
that data and ensure that all of it has been inserted appropriately.
@expected_result all items should be inserted, and verified.
@test_category queries
"""
# Table creation
table = 'wide_byte_rows'
session = self.make_session_and_keyspace()
session.execute('CREATE TABLE %s (k INT, i INT, v BLOB, PRIMARY KEY(k, i))' % table)
# Prepare statement and run insertions
to_insert = 100000
prepared = session.prepare('INSERT INTO %s (k, i, v) VALUES (0, ?, 0xCAFE)' % (table, ))
timeouts = self.batch_futures(session, (prepared.bind((i, )) for i in range(to_insert)))
# Read
results = session.execute('SELECT i, v FROM %s WHERE k=0' % (table, ))
# number of expected results
expected_results = to_insert-timeouts-1
# Verify
bb = pack('>H', 0xCAFE)
for i, row in enumerate(results):
self.assertEqual(row['v'], bb)
self.assertGreaterEqual(i, expected_results, "Verification failed only found {0} inserted we were expecting {1}".format(i,expected_results))
session.cluster.shutdown()
def test_large_text(self):
"""
Test for inserting a large text field
test_large_text tests inserting a large text field into a row.
@expected_result the large text value should be inserted. When the row is queried it should match the original
value that was inserted
@test_category queries
"""
table = 'large_text'
session = self.make_session_and_keyspace()
session.execute('CREATE TABLE %s (k int PRIMARY KEY, txt text)' % table)
# Create ultra-long text
text = 'a' * 1000000
# Write
session.execute(SimpleStatement("INSERT INTO %s (k, txt) VALUES (%s, '%s')"
% (table, 0, text),
consistency_level=ConsistencyLevel.QUORUM))
# Read
result = session.execute('SELECT * FROM %s WHERE k=%s' % (table, 0))
# Verify
found_result = False
for i, row in enumerate(result):
self.assertEqual(row['txt'], text)
found_result = True
self.assertTrue(found_result, "No results were found")
session.cluster.shutdown()
def test_wide_table(self):
table = 'wide_table'
table_width = 330
session = self.make_session_and_keyspace()
table_declaration = 'CREATE TABLE %s (key INT PRIMARY KEY, '
table_declaration += ' INT, '.join(create_column_name(i) for i in range(table_width))
table_declaration += ' INT)'
session.execute(table_declaration % table)
# Write
insert_statement = 'INSERT INTO %s (key, '
insert_statement += ', '.join(create_column_name(i) for i in range(table_width))
insert_statement += ') VALUES (%s, '
insert_statement += ', '.join(str(i) for i in range(table_width))
insert_statement += ')'
insert_statement = insert_statement % (table, 0)
session.execute(SimpleStatement(insert_statement, consistency_level=ConsistencyLevel.QUORUM))
# Read
result = session.execute('SELECT * FROM %s WHERE key=%s' % (table, 0))
# Verify
for row in result:
for i in range(table_width):
self.assertEqual(row[create_column_name(i)], i)
session.cluster.shutdown()