Permalink
Browse files

Adapt to Cassandra version to avoid CASSANDRA-8733

This Cassandra bug causes list updates to reverse the order of the
array sent, which was being worked around in List#unshift by
reversing the array that was sent.

This change detects the version of Cassandra and only reverses
when it's a known buggy version. Also, the tests detect the
version and expect a list_prepend operation to produce reversed
lists in buggy versions.

See: https://issues.apache.org/jira/browse/CASSANDRA-8733
The bug was fixed in 2.1.3 and 2.0.13.

This code depends on the .cassandra-versions file to compile
a list of buggy versions, but doesn't add any other dependencies.

The following three tests now pass:
 Cequel::Record::List#unshift should persist unloaded unshift
 Cequel::Record::List#unshift should atomically unshift
 Cequel::Metal::DataSet#list_prepend should prepend multiple elements to list column

Tested on the following versions of Cassandra:
 2.0.4
 2.0.12
 2.0.13
 2.0.16
 2.1.2
 2.1.3
 2.1.8
 2.2.1
  • Loading branch information...
lesliev committed Sep 18, 2015
1 parent 6731076 commit 3b66139a7613f09fc3749c476c1c9dfd2ee9e4bd
@@ -187,8 +187,8 @@ def decrement(deltas, options = {})
# @example
# posts.list_prepend(:categories, ['CQL', 'ORMs'])
#
# @note If multiple elements are passed, they will appear in the list in
# reverse order.
# @note A bug (CASSANDRA-8733) exists in Cassandra versions 0.3.0-2.0.12 and 2.1.0-2.1.2 which
# will make elements appear in REVERSE ORDER in the list.
# @note If a enclosed in a Keyspace#batch block, this method will be
# executed as part of the batch.
# @see #list_append
@@ -254,6 +254,32 @@ def exists?
end
end
# @return [String] Cassandra version number
def cassandra_version
return @cassandra_version if @cassandra_version
statement = <<-CQL
SELECT release_version
FROM system.local
CQL
log('CQL', statement) do
@cassandra_version = client_without_keyspace.execute(statement).first['release_version']
end
end
# return true if Cassandra server version is known to include bug CASSANDRA-8733
def bug8733_version?
version_file = File.expand_path('../../../../.cassandra-versions', __FILE__)
@all_versions ||= File.read(version_file).split("\n").map(&:strip)
# bug exists in versions 0.3.0-2.0.12 and 2.1.0-2.1.2
@bug8733_versions ||= @all_versions[0..@all_versions.index('2.0.12')] +
@all_versions[@all_versions.index('2.1.0')..@all_versions.index('2.1.2')]
@bug8733_versions.include?(cassandra_version)
end
private
attr_reader :lock
@@ -332,7 +332,8 @@ def replace(array)
#
def unshift(*objects)
objects.map!(&method(:cast_element))
to_update { updater.list_prepend(column_name, objects.reverse) }
prepared = @model.class.connection.bug8733_version? ? objects.reverse : objects
to_update { updater.list_prepend(column_name, prepared) }
to_modify { super }
end
alias_method :prepend, :unshift
@@ -191,14 +191,21 @@
)
end
# breaks in Cassandra 2.0.13+ or 2.1.3+ because reverse order bug was fixed:
# https://issues.apache.org/jira/browse/CASSANDRA-8733
it 'should prepend multiple elements to list column' do
cequel[:posts].insert(
row_keys.merge(categories: ['Big Data', 'Cassandra']))
cequel[:posts].where(row_keys).
list_prepend(:categories, ['Scalability', 'Partition Tolerance'])
expect(cequel[:posts].where(row_keys).first[:categories]).to eq(
expected = if cequel.bug8733_version?
['Partition Tolerance', 'Scalability', 'Big Data', 'Cassandra']
)
else
['Scalability', 'Partition Tolerance', 'Big Data', 'Cassandra']
end
expect(cequel[:posts].where(row_keys).first[:categories]).to eq(expected)
end
end

0 comments on commit 3b66139

Please sign in to comment.