Drop the AGPL license in favor of a source-available license. See the blog post [1] for details. [1] https://www.scylladb.com/2024/12/18/why-were-moving-to-a-source-available-license/
97 lines
5.4 KiB
Python
97 lines
5.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2023-present ScyllaDB
|
|
#
|
|
# SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0
|
|
|
|
#############################################################################
|
|
# Tests for configuration of compressed sstables
|
|
#############################################################################
|
|
|
|
import pytest
|
|
from . import nodetool
|
|
from .util import new_test_table
|
|
from cassandra.protocol import ConfigurationException, SyntaxException
|
|
|
|
# In older Cassandra and Scylla, the name of the compression algorithm was
|
|
# given as a "sstable_compression" attribute, but newer Cassandra switched
|
|
# to "class". Check that we support this new name class.
|
|
# Reproduces #8948.
|
|
@pytest.mark.xfail(reason="#8948")
|
|
def test_compression_class(cql, test_keyspace):
|
|
with new_test_table(cql, test_keyspace, "p int primary key, v int", "with compression = { 'class': 'LZ4Compressor' }") as table:
|
|
pass
|
|
|
|
# In the following tests, we use the older "sstable_compression" option name
|
|
# (instead of the new "class") so we can have passing tests despite #8948.
|
|
# When both Scylla and Cassandra support "class", we should modify this variable
|
|
# to use it:
|
|
sstable_compression = 'sstable_compression'
|
|
|
|
@pytest.fixture(scope="module")
|
|
def table_lz4(cql, test_keyspace):
|
|
with new_test_table(cql, test_keyspace, "p int primary key, v int", "with compression = { '" + sstable_compression + "': 'LZ4Compressor' }") as table:
|
|
yield table
|
|
|
|
# Test that if we have a table with lz4 compression, it has the expected
|
|
# compression "class" in its schema table. Note that even if the older
|
|
# "sstable_compression" attribute was used to set the compression class,
|
|
# when reading the schema we should see "class".
|
|
# Reproduces #8948.
|
|
@pytest.mark.xfail(reason="#8948")
|
|
def test_read_compression_class(cql, table_lz4):
|
|
[ks, cf] = table_lz4.split('.')
|
|
opts = cql.execute(f"SELECT compression FROM system_schema.tables WHERE keyspace_name='{ks}' AND table_name='{cf}'").one().compression
|
|
assert 'class' in opts
|
|
assert opts['class'] == 'org.apache.cassandra.io.compress.LZ4Compressor'
|
|
|
|
# When creating a compressed table without specifying chunk_length_in_kb
|
|
# explicitly, some default value is nevertheless used, and its value should
|
|
# be readable from the schema.
|
|
# Reproduces #6442.
|
|
@pytest.mark.xfail(reason="#6442")
|
|
def test_read_chunk_length(cql, table_lz4):
|
|
[ks, cf] = table_lz4.split('.')
|
|
opts = cql.execute(f"SELECT compression FROM system_schema.tables WHERE keyspace_name='{ks}' AND table_name='{cf}'").one().compression
|
|
assert 'chunk_length_in_kb' in opts
|
|
|
|
# Both Cassandra and Scylla only allow chunk_length_in_kb to be set a power
|
|
# of two.
|
|
def test_chunk_length_must_be_power_of_two(cql, test_keyspace):
|
|
with pytest.raises(ConfigurationException, match='power of 2'):
|
|
with new_test_table(cql, test_keyspace, "p int primary key, v int", "with compression = { '" + sstable_compression + "': 'LZ4Compressor', 'chunk_length_in_kb': 100 }") as table:
|
|
pass
|
|
|
|
# chunk_length_in_kb cannot be zero, negative, null, or non-integer.
|
|
# Surprisingly, Scylla allows floating-point numbers (and truncates them).
|
|
# It shouldn't, and Cassandra doesn't, so this case is "xfail" below.
|
|
@pytest.mark.parametrize("garbage", ["0", "-1", "null", "'dog'",
|
|
pytest.param("1.1", marks=pytest.mark.xfail(reason='Scylla truncates float chunk length'))])
|
|
def test_chunk_length_invalid(cql, test_keyspace, garbage):
|
|
# The error should usually be ConfigurationException, but strangely
|
|
# Cassandra throws a SyntaxException in the "null" case.
|
|
with pytest.raises((ConfigurationException, SyntaxException), match='chunk_length_in_kb'):
|
|
with new_test_table(cql, test_keyspace, "p int primary key, v int", "with compression = { '" + sstable_compression + "': 'LZ4Compressor', 'chunk_length_in_kb': " + garbage + " }") as table:
|
|
pass
|
|
|
|
# If a user is allowed to specify a huge number for chunk_length_in_kb, it can
|
|
# result in unbounded allocations and potentially crashing Scylla. Therefore,
|
|
# there ought to be some limit for the configured chunk length. Let's check it
|
|
# by trying a ridiculously large value, which shouldn't be legal.
|
|
# This test fails on Cassandra, which doesn't have protection against huge
|
|
# chunk sizes, so the test is marked a "cassandra_bug".
|
|
# Reproduces #9933.
|
|
def test_huge_chunk_length(cql, test_keyspace, cassandra_bug):
|
|
with pytest.raises(ConfigurationException, match='chunk_length_in_kb'):
|
|
with new_test_table(cql, test_keyspace, "p int primary key, v int", "with compression = { '" + sstable_compression + "': 'LZ4Compressor', 'chunk_length_in_kb': 1048576 }") as table:
|
|
# At this point, the test already failed, as we expected the table
|
|
# creation to have failed with ConfigurationException. But if we
|
|
# reached here, let's really demonstrate the bug - write
|
|
# something and flush it, to have sstable compression actually
|
|
# be used.
|
|
cql.execute(f'INSERT INTO {table} (p, v) VALUES (1, 2)')
|
|
nodetool.flush(cql, table)
|
|
# Also check the same for ALTER TABLE
|
|
with new_test_table(cql, test_keyspace, "p int primary key, v int") as table:
|
|
with pytest.raises(ConfigurationException, match='chunk_length_in_kb'):
|
|
cql.execute("ALTER TABLE " + table + " with compression = { '" + sstable_compression + "': 'LZ4Compressor', 'chunk_length_in_kb': 1048576 }")
|