mirror of https://github.com/apache/cassandra
Introduce created_at column to system_distributed.compression_dictionaries
patch by Stefan Miklosovic; reviewed by Yifan Cai for CASSANDRA-21178
This commit is contained in:
parent
eee06be567
commit
0be5ffa8c8
|
|
@ -1,4 +1,5 @@
|
|||
5.1
|
||||
* Introduce created_at column to system_distributed.compression_dictionaries (CASSANDRA-21178)
|
||||
* Be able to detect and remove orphaned compression dictionaries (CASSANDRA-21157)
|
||||
* Fix BigTableVerifier to only read a data file during extended verification (CASSANDRA-21150)
|
||||
* Reduce memory allocation during transformation of BatchStatement to Mutation (CASSANDRA-21141)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.io.DataInput;
|
|||
import java.io.DataOutput;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
|
@ -34,6 +35,7 @@ import com.google.common.hash.Hashing;
|
|||
import org.apache.cassandra.cql3.UntypedResultSet;
|
||||
import org.apache.cassandra.io.compress.ICompressor;
|
||||
import org.apache.cassandra.io.compress.ZstdDictionaryCompressor;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.concurrent.Ref;
|
||||
|
||||
/**
|
||||
|
|
@ -119,6 +121,14 @@ public interface CompressionDictionary
|
|||
return dictId().kind;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a date of creation of this dictionary. By creation, we mean when
|
||||
* the compression object was instantiated.
|
||||
*
|
||||
* @return when was this dictionary created.
|
||||
*/
|
||||
Instant createdAt();
|
||||
|
||||
/**
|
||||
* Returns a reference from lazily initialized reference counter.
|
||||
*
|
||||
|
|
@ -262,6 +272,7 @@ public interface CompressionDictionary
|
|||
String keyspaceName = row.getString("keyspace_name");
|
||||
String tableName = row.getString("table_name");
|
||||
String tableId = row.getString("table_id");
|
||||
Instant createdAt = row.getTimestamp("created_at").toInstant();
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -270,7 +281,8 @@ public interface CompressionDictionary
|
|||
tableId,
|
||||
new DictId(CompressionDictionary.Kind.valueOf(kindStr), dictId),
|
||||
checksum,
|
||||
size);
|
||||
size,
|
||||
createdAt);
|
||||
}
|
||||
catch (IllegalArgumentException ex)
|
||||
{
|
||||
|
|
@ -285,6 +297,7 @@ public interface CompressionDictionary
|
|||
byte[] dict = row.getByteArray("dict");
|
||||
int storedLength = row.getInt("dict_length");
|
||||
int storedChecksum = row.getInt("dict_checksum");
|
||||
Instant createdAt = row.getTimestamp("created_at").toInstant();
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -305,7 +318,7 @@ public interface CompressionDictionary
|
|||
kindStr, dictId, storedChecksum, calculatedChecksum));
|
||||
}
|
||||
|
||||
return kind.createDictionary(new DictId(kind, dictId), row.getByteArray("dict"), storedChecksum);
|
||||
return kind.createDictionary(new DictId(kind, dictId), row.getByteArray("dict"), storedChecksum, createdAt);
|
||||
}
|
||||
catch (IllegalArgumentException ex)
|
||||
{
|
||||
|
|
@ -330,9 +343,9 @@ public interface CompressionDictionary
|
|||
ZSTD
|
||||
{
|
||||
@Override
|
||||
public CompressionDictionary createDictionary(DictId dictId, byte[] dict, int checksum)
|
||||
public CompressionDictionary createDictionary(DictId dictId, byte[] dict, int checksum, Instant createdAt)
|
||||
{
|
||||
return new ZstdCompressionDictionary(dictId, dict, checksum);
|
||||
return new ZstdCompressionDictionary(dictId, dict, checksum, createdAt);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -364,7 +377,21 @@ public interface CompressionDictionary
|
|||
* @param checksum checksum of this dictionary
|
||||
* @return a compression dictionary instance
|
||||
*/
|
||||
public abstract CompressionDictionary createDictionary(CompressionDictionary.DictId dictId, byte[] dict, int checksum);
|
||||
public CompressionDictionary createDictionary(CompressionDictionary.DictId dictId, byte[] dict, int checksum)
|
||||
{
|
||||
return createDictionary(dictId, dict, checksum, FBUtilities.now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a compression dictionary instance for this kind
|
||||
*
|
||||
* @param dictId the dictionary identifier
|
||||
* @param dict the raw dictionary bytes
|
||||
* @param checksum checksum of this dictionary
|
||||
* @param createdAt creation date of to-be-constructed dictionary
|
||||
* @return a compression dictionary instance
|
||||
*/
|
||||
public abstract CompressionDictionary createDictionary(CompressionDictionary.DictId dictId, byte[] dict, int checksum, Instant createdAt);
|
||||
|
||||
/**
|
||||
* Creates a dictionary compressor for this kind
|
||||
|
|
@ -436,13 +463,15 @@ public interface CompressionDictionary
|
|||
public final DictId dictId;
|
||||
public final int checksum;
|
||||
public final int size;
|
||||
public final Instant createdAt;
|
||||
|
||||
public LightweightCompressionDictionary(String keyspaceName,
|
||||
String tableName,
|
||||
String tableId,
|
||||
DictId dictId,
|
||||
int checksum,
|
||||
int size)
|
||||
int size,
|
||||
Instant createdAt)
|
||||
{
|
||||
this.keyspaceName = keyspaceName;
|
||||
this.tableName = tableName;
|
||||
|
|
@ -450,6 +479,7 @@ public interface CompressionDictionary
|
|||
this.dictId = dictId;
|
||||
this.checksum = checksum;
|
||||
this.size = size;
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -462,6 +492,7 @@ public interface CompressionDictionary
|
|||
", dictId=" + dictId +
|
||||
", checksum=" + checksum +
|
||||
", size=" + size +
|
||||
", createdAt=" + createdAt +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
package org.apache.cassandra.db.compression;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.management.openmbean.ArrayType;
|
||||
|
|
@ -33,7 +34,6 @@ import com.fasterxml.jackson.annotation.JsonCreator;
|
|||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import org.apache.cassandra.db.compression.CompressionDictionary.LightweightCompressionDictionary;
|
||||
import org.apache.cassandra.io.util.FileUtils;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ public class CompressionDictionaryDetailsTabularData
|
|||
public static final String KIND_NAME = "Kind";
|
||||
public static final String CHECKSUM_NAME = "Checksum";
|
||||
public static final String SIZE_NAME = "Size";
|
||||
|
||||
public static final String CREATED_AT_NAME = "CreatedAt";
|
||||
|
||||
private static final String[] ITEM_NAMES = new String[]{ KEYSPACE_NAME,
|
||||
TABLE_NAME,
|
||||
|
|
@ -72,7 +72,8 @@ public class CompressionDictionaryDetailsTabularData
|
|||
DICT_NAME,
|
||||
KIND_NAME,
|
||||
CHECKSUM_NAME,
|
||||
SIZE_NAME };
|
||||
SIZE_NAME,
|
||||
CREATED_AT_NAME };
|
||||
|
||||
private static final String[] ITEM_DESCS = new String[]{ "keyspace",
|
||||
"table",
|
||||
|
|
@ -81,7 +82,8 @@ public class CompressionDictionaryDetailsTabularData
|
|||
"dictionary_bytes",
|
||||
"kind",
|
||||
"checksum",
|
||||
"size" };
|
||||
"size",
|
||||
"created_at" };
|
||||
|
||||
private static final String TYPE_NAME = "DictionaryDetails";
|
||||
private static final String ROW_DESC = "DictionaryDetails";
|
||||
|
|
@ -100,7 +102,8 @@ public class CompressionDictionaryDetailsTabularData
|
|||
new ArrayType<String[]>(SimpleType.BYTE, true), // dict bytes
|
||||
SimpleType.STRING, // kind
|
||||
SimpleType.INTEGER, // checksum
|
||||
SimpleType.INTEGER }; // size of dict bytes
|
||||
SimpleType.INTEGER, // size of dict bytes
|
||||
SimpleType.STRING }; // created_at
|
||||
|
||||
COMPOSITE_TYPE = new CompositeType(TYPE_NAME, ROW_DESC, ITEM_NAMES, ITEM_DESCS, ITEM_TYPES);
|
||||
TABULAR_TYPE = new TabularType(TYPE_NAME, ROW_DESC, COMPOSITE_TYPE, ITEM_NAMES);
|
||||
|
|
@ -133,6 +136,7 @@ public class CompressionDictionaryDetailsTabularData
|
|||
dictionary.dictId.kind.name(),
|
||||
dictionary.checksum,
|
||||
dictionary.size,
|
||||
dictionary.createdAt.toString()
|
||||
});
|
||||
}
|
||||
catch (OpenDataException e)
|
||||
|
|
@ -166,6 +170,7 @@ public class CompressionDictionaryDetailsTabularData
|
|||
dictionary.kind().name(),
|
||||
dictionary.checksum(),
|
||||
dictionary.rawDictionary().length,
|
||||
dictionary.createdAt().toString(),
|
||||
});
|
||||
}
|
||||
catch (OpenDataException e)
|
||||
|
|
@ -196,7 +201,8 @@ public class CompressionDictionaryDetailsTabularData
|
|||
dataObject.dict,
|
||||
dataObject.kind,
|
||||
dataObject.dictChecksum,
|
||||
dataObject.dictLength
|
||||
dataObject.dictLength,
|
||||
dataObject.createdAt.toString()
|
||||
});
|
||||
}
|
||||
catch (OpenDataException e)
|
||||
|
|
@ -221,7 +227,8 @@ public class CompressionDictionaryDetailsTabularData
|
|||
(byte[]) compositeData.get(CompressionDictionaryDetailsTabularData.DICT_NAME),
|
||||
(String) compositeData.get(CompressionDictionaryDetailsTabularData.KIND_NAME),
|
||||
(Integer) compositeData.get(CompressionDictionaryDetailsTabularData.CHECKSUM_NAME),
|
||||
(Integer) compositeData.get(CompressionDictionaryDetailsTabularData.SIZE_NAME));
|
||||
(Integer) compositeData.get(CompressionDictionaryDetailsTabularData.SIZE_NAME),
|
||||
Instant.parse((String) compositeData.get(CompressionDictionaryDetailsTabularData.CREATED_AT_NAME)));
|
||||
}
|
||||
|
||||
public static class CompressionDictionaryDataObject
|
||||
|
|
@ -234,6 +241,7 @@ public class CompressionDictionaryDetailsTabularData
|
|||
public final String kind;
|
||||
public final int dictChecksum;
|
||||
public final int dictLength;
|
||||
public final Instant createdAt;
|
||||
|
||||
@JsonCreator
|
||||
public CompressionDictionaryDataObject(@JsonProperty("keyspace") String keyspace,
|
||||
|
|
@ -243,7 +251,8 @@ public class CompressionDictionaryDetailsTabularData
|
|||
@JsonProperty("dict") byte[] dict,
|
||||
@JsonProperty("kind") String kind,
|
||||
@JsonProperty("dictChecksum") int dictChecksum,
|
||||
@JsonProperty("dictLength") int dictLength)
|
||||
@JsonProperty("dictLength") int dictLength,
|
||||
@JsonProperty("createdAt") Instant createdAt)
|
||||
{
|
||||
this.keyspace = keyspace;
|
||||
this.table = table;
|
||||
|
|
@ -253,6 +262,7 @@ public class CompressionDictionaryDetailsTabularData
|
|||
this.kind = kind;
|
||||
this.dictChecksum = dictChecksum;
|
||||
this.dictLength = dictLength;
|
||||
this.createdAt = createdAt;
|
||||
|
||||
validate();
|
||||
}
|
||||
|
|
@ -269,6 +279,7 @@ public class CompressionDictionaryDetailsTabularData
|
|||
* <li>dictLength is bigger than 0</li>
|
||||
* <li>dictLength has to be equal to dict's length</li>
|
||||
* <li>dictChecksum has to be equal to checksum computed as part of this method</li>
|
||||
* <li>creation date is not null</li>
|
||||
* </ul>
|
||||
*/
|
||||
private void validate()
|
||||
|
|
@ -278,15 +289,11 @@ public class CompressionDictionaryDetailsTabularData
|
|||
if (table == null)
|
||||
throw new IllegalArgumentException("Table not specified.");
|
||||
if (tableId == null)
|
||||
throw new IllegalArgumentException("Table id not specified");
|
||||
throw new IllegalArgumentException("Table id not specified.");
|
||||
if (dictId <= 0)
|
||||
throw new IllegalArgumentException("Provided dictionary id must be positive but it is '" + dictId + "'.");
|
||||
if (dict == null || dict.length == 0)
|
||||
throw new IllegalArgumentException("Provided dictionary byte array is null or empty.");
|
||||
if (dict.length > FileUtils.ONE_MIB)
|
||||
throw new IllegalArgumentException("Imported dictionary can not be larger than " +
|
||||
FileUtils.ONE_MIB + " bytes, but it is " +
|
||||
dict.length + " bytes.");
|
||||
if (kind == null)
|
||||
throw new IllegalArgumentException("Provided kind is null.");
|
||||
|
||||
|
|
@ -305,6 +312,8 @@ public class CompressionDictionaryDetailsTabularData
|
|||
throw new IllegalArgumentException("Size has to be strictly positive number, it is '" + dictLength + "'.");
|
||||
if (dict.length != dictLength)
|
||||
throw new IllegalArgumentException("The length of the provided dictionary array (" + dict.length + ") is not equal to provided length value (" + dictLength + ").");
|
||||
if (createdAt == null)
|
||||
throw new IllegalArgumentException("The creation date not specified.");
|
||||
|
||||
int checksumOfDictionaryToImport = CompressionDictionary.calculateChecksum((byte) dictionaryKind.ordinal(), dictId, dict);
|
||||
if (checksumOfDictionaryToImport != dictChecksum)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
package org.apache.cassandra.db.compression;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
|
@ -30,6 +31,7 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.cassandra.io.compress.ZstdCompressorBase;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.concurrent.Ref;
|
||||
import org.apache.cassandra.utils.concurrent.RefCounted;
|
||||
import org.apache.cassandra.utils.concurrent.SelfRefCounted;
|
||||
|
|
@ -45,21 +47,24 @@ public class ZstdCompressionDictionary implements CompressionDictionary, SelfRef
|
|||
private final ConcurrentHashMap<Integer, ZstdDictCompress> zstdDictCompressPerLevel = new ConcurrentHashMap<>();
|
||||
private final AtomicReference<ZstdDictDecompress> dictDecompress = new AtomicReference<>();
|
||||
private volatile Ref<ZstdCompressionDictionary> selfRef;
|
||||
private final Instant createdAt;
|
||||
|
||||
@VisibleForTesting
|
||||
public ZstdCompressionDictionary(DictId dictId, byte[] rawDictionary)
|
||||
{
|
||||
this(dictId,
|
||||
rawDictionary,
|
||||
CompressionDictionary.calculateChecksum((byte) dictId.kind.ordinal(), dictId.id, rawDictionary));
|
||||
CompressionDictionary.calculateChecksum((byte) dictId.kind.ordinal(), dictId.id, rawDictionary),
|
||||
FBUtilities.now());
|
||||
}
|
||||
|
||||
public ZstdCompressionDictionary(DictId dictId, byte[] rawDictionary, int checksum)
|
||||
public ZstdCompressionDictionary(DictId dictId, byte[] rawDictionary, int checksum, Instant createdAt)
|
||||
{
|
||||
this.dictId = dictId;
|
||||
this.rawDictionary = rawDictionary;
|
||||
this.checksum = checksum;
|
||||
this.selfRef = null;
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -86,6 +91,12 @@ public class ZstdCompressionDictionary implements CompressionDictionary, SelfRef
|
|||
return checksum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant createdAt()
|
||||
{
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int estimatedOccupiedMemoryBytes()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ import org.apache.cassandra.locator.InetAddressAndPort;
|
|||
import org.apache.cassandra.repair.CommonRange;
|
||||
import org.apache.cassandra.repair.messages.RepairOption;
|
||||
import org.apache.cassandra.tcm.ClusterMetadata;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.TimeUUID;
|
||||
|
||||
|
|
@ -206,6 +207,7 @@ public final class SystemDistributedKeyspace
|
|||
"dict blob," +
|
||||
"dict_length int," +
|
||||
"dict_checksum int," +
|
||||
"created_at timestamp," +
|
||||
"PRIMARY KEY ((keyspace_name, table_name), table_id, dict_id)) " +
|
||||
"WITH CLUSTERING ORDER BY (table_id DESC, dict_id DESC)"; // in order to retrieve the latest dictionary; the contract is the newer the dictionary the larger the dict_id
|
||||
|
||||
|
|
@ -426,7 +428,7 @@ public final class SystemDistributedKeyspace
|
|||
CompressionDictionary dictionary)
|
||||
{
|
||||
byte[] dict = dictionary.rawDictionary();
|
||||
String query = "INSERT INTO %s.%s (keyspace_name, table_name, table_id, kind, dict_id, dict, dict_length, dict_checksum) VALUES ('%s', '%s', '%s', '%s', %s, ?, %s, %s)";
|
||||
String query = "INSERT INTO %s.%s (keyspace_name, table_name, table_id, kind, dict_id, dict, dict_length, dict_checksum, created_at) VALUES ('%s', '%s', '%s', '%s', %s, ?, %s, %s, ?)";
|
||||
String fmtQuery = format(query,
|
||||
SchemaConstants.DISTRIBUTED_KEYSPACE_NAME,
|
||||
COMPRESSION_DICTIONARIES,
|
||||
|
|
@ -439,7 +441,7 @@ public final class SystemDistributedKeyspace
|
|||
dictionary.checksum());
|
||||
noThrow(fmtQuery,
|
||||
() -> QueryProcessor.process(fmtQuery, ConsistencyLevel.ONE,
|
||||
Collections.singletonList(ByteBuffer.wrap(dict))));
|
||||
List.of(ByteBuffer.wrap(dict), ByteBufferUtil.bytes(dictionary.createdAt().toEpochMilli()))));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -454,7 +456,7 @@ public final class SystemDistributedKeyspace
|
|||
@Nullable
|
||||
public static CompressionDictionary retrieveLatestCompressionDictionary(String keyspaceName, String tableName, String tableId)
|
||||
{
|
||||
String query = "SELECT kind, dict_id, dict, dict_length, dict_checksum FROM %s.%s WHERE keyspace_name='%s' AND table_name='%s' AND table_id='%s' LIMIT 1";
|
||||
String query = "SELECT kind, dict_id, dict, dict_length, dict_checksum, created_at FROM %s.%s WHERE keyspace_name='%s' AND table_name='%s' AND table_id='%s' LIMIT 1";
|
||||
String fmtQuery = format(query, SchemaConstants.DISTRIBUTED_KEYSPACE_NAME, COMPRESSION_DICTIONARIES, keyspaceName, tableName, tableId);
|
||||
try
|
||||
{
|
||||
|
|
@ -479,7 +481,7 @@ public final class SystemDistributedKeyspace
|
|||
@Nullable
|
||||
public static LightweightCompressionDictionary retrieveLightweightLatestCompressionDictionary(String keyspaceName, String tableName, String tableId)
|
||||
{
|
||||
String query = "SELECT keyspace_name, table_name, table_id, kind, dict_id, dict_checksum, dict_length FROM %s.%s WHERE keyspace_name='%s' AND table_name='%s' AND table_id='%s' LIMIT 1";
|
||||
String query = "SELECT keyspace_name, table_name, table_id, kind, dict_id, dict_checksum, dict_length, created_at FROM %s.%s WHERE keyspace_name='%s' AND table_name='%s' AND table_id='%s' LIMIT 1";
|
||||
String fmtQuery = format(query, SchemaConstants.DISTRIBUTED_KEYSPACE_NAME, COMPRESSION_DICTIONARIES, keyspaceName, tableName, tableId);
|
||||
try
|
||||
{
|
||||
|
|
@ -505,7 +507,7 @@ public final class SystemDistributedKeyspace
|
|||
@Nullable
|
||||
public static CompressionDictionary retrieveCompressionDictionary(String keyspaceName, String tableName, String tableId, long dictionaryId)
|
||||
{
|
||||
String query = "SELECT kind, dict_id, dict, dict_length, dict_checksum FROM %s.%s WHERE keyspace_name='%s' AND table_name='%s' AND table_id='%s' AND dict_id=%s";
|
||||
String query = "SELECT kind, dict_id, dict, dict_length, dict_checksum, created_at FROM %s.%s WHERE keyspace_name='%s' AND table_name='%s' AND table_id='%s' AND dict_id=%s";
|
||||
String fmtQuery = format(query, SchemaConstants.DISTRIBUTED_KEYSPACE_NAME, COMPRESSION_DICTIONARIES, keyspaceName, tableName, tableId, dictionaryId);
|
||||
try
|
||||
{
|
||||
|
|
@ -529,7 +531,7 @@ public final class SystemDistributedKeyspace
|
|||
@Nullable
|
||||
public static List<LightweightCompressionDictionary> retrieveLightweightCompressionDictionaries(String keyspaceName, String tableName, String tableId)
|
||||
{
|
||||
String query = "SELECT keyspace_name, table_name, table_id, kind, dict_id, dict_length, dict_checksum FROM %s.%s WHERE keyspace_name='%s' AND table_name='%s' AND table_id='%s'";
|
||||
String query = "SELECT keyspace_name, table_name, table_id, kind, dict_id, dict_length, dict_checksum, created_at FROM %s.%s WHERE keyspace_name='%s' AND table_name='%s' AND table_id='%s'";
|
||||
String fmtQuery = format(query, SchemaConstants.DISTRIBUTED_KEYSPACE_NAME, COMPRESSION_DICTIONARIES, keyspaceName, tableName, tableId);
|
||||
return retrieveLightweightCompressionDictionariesInternal(fmtQuery);
|
||||
}
|
||||
|
|
@ -543,7 +545,7 @@ public final class SystemDistributedKeyspace
|
|||
@Nullable
|
||||
public static List<LightweightCompressionDictionary> retrieveLightweightCompressionDictionaries()
|
||||
{
|
||||
String query = "SELECT keyspace_name, table_name, table_id, kind, dict_id, dict_length, dict_checksum FROM %s.%s";
|
||||
String query = "SELECT keyspace_name, table_name, table_id, kind, dict_id, dict_length, dict_checksum, created_at FROM %s.%s";
|
||||
String fmtQuery = format(query, SchemaConstants.DISTRIBUTED_KEYSPACE_NAME, COMPRESSION_DICTIONARIES);
|
||||
return retrieveLightweightCompressionDictionariesInternal(fmtQuery);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
package org.apache.cassandra.db.compression;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
|
@ -27,7 +28,6 @@ import org.junit.Test;
|
|||
|
||||
import org.apache.cassandra.db.compression.CompressionDictionary.LightweightCompressionDictionary;
|
||||
import org.apache.cassandra.db.compression.CompressionDictionaryDetailsTabularData.CompressionDictionaryDataObject;
|
||||
import org.apache.cassandra.io.util.FileUtils;
|
||||
import org.apache.cassandra.utils.CompressionDictionaryHelper;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
|
@ -40,6 +40,7 @@ public class CompressionDictionaryDataObjectTest
|
|||
private static final String KEYSPACE = "ks";
|
||||
private static final String TABLE = "tb";
|
||||
private static final String TABLE_ID = UUID.randomUUID().toString();
|
||||
private static final Instant now = Instant.now();
|
||||
private static final CompressionDictionary COMPRESSION_DICTIONARY = CompressionDictionaryHelper.INSTANCE.trainDictionary(KEYSPACE, TABLE);
|
||||
private static final CompressionDictionaryDataObject VALID_OBJECT = createValidObject();
|
||||
|
||||
|
|
@ -56,6 +57,7 @@ public class CompressionDictionaryDataObjectTest
|
|||
assertEquals(VALID_OBJECT.kind, dataObject.kind);
|
||||
assertEquals(VALID_OBJECT.dictChecksum, dataObject.dictChecksum);
|
||||
assertEquals(VALID_OBJECT.dictLength, dataObject.dictLength);
|
||||
assertEquals(VALID_OBJECT.createdAt, dataObject.createdAt);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -71,6 +73,7 @@ public class CompressionDictionaryDataObjectTest
|
|||
assertEquals(COMPRESSION_DICTIONARY.kind().name(), dataObject.kind);
|
||||
assertEquals(COMPRESSION_DICTIONARY.checksum(), dataObject.dictChecksum);
|
||||
assertEquals(COMPRESSION_DICTIONARY.rawDictionary().length, dataObject.dictLength);
|
||||
assertEquals(COMPRESSION_DICTIONARY.createdAt(), dataObject.createdAt);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -81,7 +84,8 @@ public class CompressionDictionaryDataObjectTest
|
|||
TABLE_ID,
|
||||
COMPRESSION_DICTIONARY.dictId(),
|
||||
COMPRESSION_DICTIONARY.checksum(),
|
||||
COMPRESSION_DICTIONARY.rawDictionary().length);
|
||||
COMPRESSION_DICTIONARY.rawDictionary().length,
|
||||
now);
|
||||
|
||||
CompositeData compositeData = CompressionDictionaryDetailsTabularData.fromLightweightCompressionDictionary(lightweight);
|
||||
|
||||
|
|
@ -93,6 +97,7 @@ public class CompressionDictionaryDataObjectTest
|
|||
assertEquals(COMPRESSION_DICTIONARY.dictId().kind.name(), compositeData.get(CompressionDictionaryDetailsTabularData.KIND_NAME));
|
||||
assertEquals(COMPRESSION_DICTIONARY.checksum(), compositeData.get(CompressionDictionaryDetailsTabularData.CHECKSUM_NAME));
|
||||
assertEquals(COMPRESSION_DICTIONARY.rawDictionary().length, compositeData.get(CompressionDictionaryDetailsTabularData.SIZE_NAME));
|
||||
assertEquals(now.toString(), compositeData.get(CompressionDictionaryDetailsTabularData.CREATED_AT_NAME));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -100,13 +105,10 @@ public class CompressionDictionaryDataObjectTest
|
|||
{
|
||||
assertInvalid(modifier -> modifier.withKeyspace(null), "Keyspace not specified.");
|
||||
assertInvalid(modifier -> modifier.withTable(null), "Table not specified.");
|
||||
assertInvalid(modifier -> modifier.withTableId(null), "Table id not specified");
|
||||
assertInvalid(modifier -> modifier.withTableId(null), "Table id not specified.");
|
||||
assertInvalid(modifier -> modifier.withDictId(-1), "Provided dictionary id must be positive but it is '-1'.");
|
||||
assertInvalid(modifier -> modifier.withDict(null), "Provided dictionary byte array is null or empty.");
|
||||
assertInvalid(modifier -> modifier.withDict(new byte[0]), "Provided dictionary byte array is null or empty.");
|
||||
assertInvalid(modifier -> modifier.withDict(new byte[((int) FileUtils.ONE_MIB) + 1]),
|
||||
"Imported dictionary can not be larger than 1048576 bytes, but it is 1048577 bytes.");
|
||||
assertInvalid(modifier -> modifier.withKind(null), "Provided kind is null.");
|
||||
assertInvalid(modifier -> modifier.withDict(new byte[0]), "Provided dictionary byte array is null or empty.");assertInvalid(modifier -> modifier.withKind(null), "Provided kind is null.");
|
||||
assertInvalid(modifier -> modifier.withKind("NONSENSE"), "There is no such dictionary kind like 'NONSENSE'. Available kinds: [ZSTD]");
|
||||
assertInvalid(modifier -> modifier.withDictLength(0), "Size has to be strictly positive number, it is '0'.");
|
||||
assertInvalid(modifier -> modifier.withDictLength(-10), "Size has to be strictly positive number, it is '-10'.");
|
||||
|
|
@ -116,6 +118,7 @@ public class CompressionDictionaryDataObjectTest
|
|||
assertInvalid(builder -> builder.withDictChecksum(VALID_OBJECT.dictChecksum + 1),
|
||||
"Computed checksum of dictionary to import (" + VALID_OBJECT.dictChecksum +
|
||||
") is different from checksum specified on input (" + (VALID_OBJECT.dictChecksum + 1) + ").");
|
||||
assertInvalid(modifier -> modifier.withCreatedAt(null), "The creation date not specified.");
|
||||
}
|
||||
|
||||
private void assertInvalid(Consumer<DataObjectModifier> action, String expectedExceptionMessage)
|
||||
|
|
@ -130,6 +133,7 @@ public class CompressionDictionaryDataObjectTest
|
|||
|
||||
private static CompressionDictionaryDataObject createValidObject()
|
||||
{
|
||||
|
||||
return new CompressionDictionaryDataObject("ks",
|
||||
"tb",
|
||||
TABLE_ID,
|
||||
|
|
@ -139,7 +143,8 @@ public class CompressionDictionaryDataObjectTest
|
|||
CompressionDictionary.calculateChecksum((byte) CompressionDictionary.Kind.ZSTD.ordinal(),
|
||||
123,
|
||||
COMPRESSION_DICTIONARY.rawDictionary()),
|
||||
COMPRESSION_DICTIONARY.rawDictionary().length);
|
||||
COMPRESSION_DICTIONARY.rawDictionary().length,
|
||||
now);
|
||||
}
|
||||
|
||||
private static class DataObjectModifier
|
||||
|
|
@ -152,6 +157,7 @@ public class CompressionDictionaryDataObjectTest
|
|||
private String kind;
|
||||
private int dictChecksum;
|
||||
private int dictLength;
|
||||
private Instant createdAt;
|
||||
|
||||
public DataObjectModifier(CompressionDictionaryDataObject from)
|
||||
{
|
||||
|
|
@ -163,11 +169,12 @@ public class CompressionDictionaryDataObjectTest
|
|||
withKind(from.kind);
|
||||
withDictChecksum(from.dictChecksum);
|
||||
withDictLength(from.dictLength);
|
||||
withCreatedAt(from.createdAt);
|
||||
}
|
||||
|
||||
public CompressionDictionaryDataObject build()
|
||||
{
|
||||
return new CompressionDictionaryDataObject(keyspace, table, tableId, dictId, dict, kind, dictChecksum, dictLength);
|
||||
return new CompressionDictionaryDataObject(keyspace, table, tableId, dictId, dict, kind, dictChecksum, dictLength, createdAt);
|
||||
}
|
||||
|
||||
public DataObjectModifier withKeyspace(String keyspace)
|
||||
|
|
@ -217,5 +224,11 @@ public class CompressionDictionaryDataObjectTest
|
|||
this.dictLength = dictLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
private DataObjectModifier withCreatedAt(Instant createdAt)
|
||||
{
|
||||
this.createdAt = createdAt;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.time.Instant;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
|
|
@ -92,7 +93,8 @@ public class ExportImportListCompressionDictionaryTest extends CQLTester
|
|||
pair.left.dict,
|
||||
pair.left.kind,
|
||||
pair.left.dictChecksum,
|
||||
pair.left.dictLength), pair.right);
|
||||
pair.left.dictLength,
|
||||
Instant.now()), pair.right);
|
||||
|
||||
ToolResult result = invokeNodetool("compressiondictionary", "import", pair.right.absolutePath());
|
||||
assertTrue(result.getStderr().contains("Unable to import dictionary JSON: Table abc.def does not exist or does not support dictionary compression"));
|
||||
|
|
@ -168,10 +170,11 @@ public class ExportImportListCompressionDictionaryTest extends CQLTester
|
|||
ToolResult result = invokeNodetool("compressiondictionary", "list", keyspace(), table);
|
||||
result.assertOnExitCode();
|
||||
assertTrue(result.getStdout()
|
||||
.contains(format("%s %s %s %s %s %s",
|
||||
.contains(format("%s %s %s %s %s %s %s",
|
||||
keyspace(), table, dataObject.dictId,
|
||||
dataObject.kind, dataObject.dictChecksum,
|
||||
dataObject.dictLength)));
|
||||
dataObject.dictLength,
|
||||
dataObject.createdAt.toString())));
|
||||
}
|
||||
|
||||
private void rewriteTable(String table, Pair<CompressionDictionaryDataObject, File> pair) throws Throwable
|
||||
|
|
@ -183,7 +186,8 @@ public class ExportImportListCompressionDictionaryTest extends CQLTester
|
|||
pair.left.dict,
|
||||
pair.left.kind,
|
||||
pair.left.dictChecksum,
|
||||
pair.left.dictLength),
|
||||
pair.left.dictLength,
|
||||
pair.left.createdAt),
|
||||
pair.right);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue