diff --git a/CHANGES.txt b/CHANGES.txt index 0b32a66928..0e0cc24c92 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -34,6 +34,8 @@ * Fix broken paging state with prepared statement (CASSANDRA-7120) * Fix IllegalArgumentException in CqlStorage (CASSANDRA-7287) * Allow nulls/non-existant fields in UDT (CASSANDRA-7206) + * Backport Thrift MultiSliceRequest (CASSANDRA-7027) + * Handle overlapping MultiSlices (CASSANDRA-7279) Merged from 2.0: * Copy compaction options to make sure they are reloaded (CASSANDRA-7290) * Add option to do more aggressive tombstone compactions (CASSANDRA-6563) diff --git a/interface/thrift/gen-java/org/apache/cassandra/thrift/CfDef.java b/interface/thrift/gen-java/org/apache/cassandra/thrift/CfDef.java index 4f6912e1a8..ec10050238 100644 --- a/interface/thrift/gen-java/org/apache/cassandra/thrift/CfDef.java +++ b/interface/thrift/gen-java/org/apache/cassandra/thrift/CfDef.java @@ -78,7 +78,6 @@ public class CfDef implements org.apache.thrift.TBase, jav private static final org.apache.thrift.protocol.TField BLOOM_FILTER_FP_CHANCE_FIELD_DESC = new org.apache.thrift.protocol.TField("bloom_filter_fp_chance", org.apache.thrift.protocol.TType.DOUBLE, (short)33); private static final org.apache.thrift.protocol.TField CACHING_FIELD_DESC = new org.apache.thrift.protocol.TField("caching", org.apache.thrift.protocol.TType.STRING, (short)34); private static final org.apache.thrift.protocol.TField DCLOCAL_READ_REPAIR_CHANCE_FIELD_DESC = new org.apache.thrift.protocol.TField("dclocal_read_repair_chance", org.apache.thrift.protocol.TType.DOUBLE, (short)37); - private static final org.apache.thrift.protocol.TField POPULATE_IO_CACHE_ON_FLUSH_FIELD_DESC = new org.apache.thrift.protocol.TField("populate_io_cache_on_flush", org.apache.thrift.protocol.TType.BOOL, (short)38); private static final org.apache.thrift.protocol.TField MEMTABLE_FLUSH_PERIOD_IN_MS_FIELD_DESC = new org.apache.thrift.protocol.TField("memtable_flush_period_in_ms", org.apache.thrift.protocol.TType.I32, (short)39); private static final org.apache.thrift.protocol.TField DEFAULT_TIME_TO_LIVE_FIELD_DESC = new org.apache.thrift.protocol.TField("default_time_to_live", org.apache.thrift.protocol.TType.I32, (short)40); private static final org.apache.thrift.protocol.TField SPECULATIVE_RETRY_FIELD_DESC = new org.apache.thrift.protocol.TField("speculative_retry", org.apache.thrift.protocol.TType.STRING, (short)42); @@ -97,6 +96,7 @@ public class CfDef implements org.apache.thrift.TBase, jav private static final org.apache.thrift.protocol.TField MERGE_SHARDS_CHANCE_FIELD_DESC = new org.apache.thrift.protocol.TField("merge_shards_chance", org.apache.thrift.protocol.TType.DOUBLE, (short)25); private static final org.apache.thrift.protocol.TField ROW_CACHE_PROVIDER_FIELD_DESC = new org.apache.thrift.protocol.TField("row_cache_provider", org.apache.thrift.protocol.TType.STRING, (short)27); private static final org.apache.thrift.protocol.TField ROW_CACHE_KEYS_TO_SAVE_FIELD_DESC = new org.apache.thrift.protocol.TField("row_cache_keys_to_save", org.apache.thrift.protocol.TType.I32, (short)31); + private static final org.apache.thrift.protocol.TField POPULATE_IO_CACHE_ON_FLUSH_FIELD_DESC = new org.apache.thrift.protocol.TField("populate_io_cache_on_flush", org.apache.thrift.protocol.TType.BOOL, (short)38); private static final org.apache.thrift.protocol.TField INDEX_INTERVAL_FIELD_DESC = new org.apache.thrift.protocol.TField("index_interval", org.apache.thrift.protocol.TType.I32, (short)41); private static final Map, SchemeFactory> schemes = new HashMap, SchemeFactory>(); @@ -126,7 +126,6 @@ public class CfDef implements org.apache.thrift.TBase, jav public double bloom_filter_fp_chance; // optional public String caching; // optional public double dclocal_read_repair_chance; // optional - public boolean populate_io_cache_on_flush; // optional public int memtable_flush_period_in_ms; // optional public int default_time_to_live; // optional public String speculative_retry; // optional @@ -178,6 +177,10 @@ public class CfDef implements org.apache.thrift.TBase, jav * @deprecated */ public int row_cache_keys_to_save; // optional + /** + * @deprecated + */ + public boolean populate_io_cache_on_flush; // optional /** * @deprecated */ @@ -206,7 +209,6 @@ public class CfDef implements org.apache.thrift.TBase, jav BLOOM_FILTER_FP_CHANCE((short)33, "bloom_filter_fp_chance"), CACHING((short)34, "caching"), DCLOCAL_READ_REPAIR_CHANCE((short)37, "dclocal_read_repair_chance"), - POPULATE_IO_CACHE_ON_FLUSH((short)38, "populate_io_cache_on_flush"), MEMTABLE_FLUSH_PERIOD_IN_MS((short)39, "memtable_flush_period_in_ms"), DEFAULT_TIME_TO_LIVE((short)40, "default_time_to_live"), SPECULATIVE_RETRY((short)42, "speculative_retry"), @@ -258,6 +260,10 @@ public class CfDef implements org.apache.thrift.TBase, jav * @deprecated */ ROW_CACHE_KEYS_TO_SAVE((short)31, "row_cache_keys_to_save"), + /** + * @deprecated + */ + POPULATE_IO_CACHE_ON_FLUSH((short)38, "populate_io_cache_on_flush"), /** * @deprecated */ @@ -318,8 +324,6 @@ public class CfDef implements org.apache.thrift.TBase, jav return CACHING; case 37: // DCLOCAL_READ_REPAIR_CHANCE return DCLOCAL_READ_REPAIR_CHANCE; - case 38: // POPULATE_IO_CACHE_ON_FLUSH - return POPULATE_IO_CACHE_ON_FLUSH; case 39: // MEMTABLE_FLUSH_PERIOD_IN_MS return MEMTABLE_FLUSH_PERIOD_IN_MS; case 40: // DEFAULT_TIME_TO_LIVE @@ -356,6 +360,8 @@ public class CfDef implements org.apache.thrift.TBase, jav return ROW_CACHE_PROVIDER; case 31: // ROW_CACHE_KEYS_TO_SAVE return ROW_CACHE_KEYS_TO_SAVE; + case 38: // POPULATE_IO_CACHE_ON_FLUSH + return POPULATE_IO_CACHE_ON_FLUSH; case 41: // INDEX_INTERVAL return INDEX_INTERVAL; default: @@ -405,24 +411,24 @@ public class CfDef implements org.apache.thrift.TBase, jav private static final int __MAX_COMPACTION_THRESHOLD_ISSET_ID = 4; private static final int __BLOOM_FILTER_FP_CHANCE_ISSET_ID = 5; private static final int __DCLOCAL_READ_REPAIR_CHANCE_ISSET_ID = 6; - private static final int __POPULATE_IO_CACHE_ON_FLUSH_ISSET_ID = 7; - private static final int __MEMTABLE_FLUSH_PERIOD_IN_MS_ISSET_ID = 8; - private static final int __DEFAULT_TIME_TO_LIVE_ISSET_ID = 9; - private static final int __MIN_INDEX_INTERVAL_ISSET_ID = 10; - private static final int __MAX_INDEX_INTERVAL_ISSET_ID = 11; - private static final int __ROW_CACHE_SIZE_ISSET_ID = 12; - private static final int __KEY_CACHE_SIZE_ISSET_ID = 13; - private static final int __ROW_CACHE_SAVE_PERIOD_IN_SECONDS_ISSET_ID = 14; - private static final int __KEY_CACHE_SAVE_PERIOD_IN_SECONDS_ISSET_ID = 15; - private static final int __MEMTABLE_FLUSH_AFTER_MINS_ISSET_ID = 16; - private static final int __MEMTABLE_THROUGHPUT_IN_MB_ISSET_ID = 17; - private static final int __MEMTABLE_OPERATIONS_IN_MILLIONS_ISSET_ID = 18; - private static final int __REPLICATE_ON_WRITE_ISSET_ID = 19; - private static final int __MERGE_SHARDS_CHANCE_ISSET_ID = 20; - private static final int __ROW_CACHE_KEYS_TO_SAVE_ISSET_ID = 21; + private static final int __MEMTABLE_FLUSH_PERIOD_IN_MS_ISSET_ID = 7; + private static final int __DEFAULT_TIME_TO_LIVE_ISSET_ID = 8; + private static final int __MIN_INDEX_INTERVAL_ISSET_ID = 9; + private static final int __MAX_INDEX_INTERVAL_ISSET_ID = 10; + private static final int __ROW_CACHE_SIZE_ISSET_ID = 11; + private static final int __KEY_CACHE_SIZE_ISSET_ID = 12; + private static final int __ROW_CACHE_SAVE_PERIOD_IN_SECONDS_ISSET_ID = 13; + private static final int __KEY_CACHE_SAVE_PERIOD_IN_SECONDS_ISSET_ID = 14; + private static final int __MEMTABLE_FLUSH_AFTER_MINS_ISSET_ID = 15; + private static final int __MEMTABLE_THROUGHPUT_IN_MB_ISSET_ID = 16; + private static final int __MEMTABLE_OPERATIONS_IN_MILLIONS_ISSET_ID = 17; + private static final int __REPLICATE_ON_WRITE_ISSET_ID = 18; + private static final int __MERGE_SHARDS_CHANCE_ISSET_ID = 19; + private static final int __ROW_CACHE_KEYS_TO_SAVE_ISSET_ID = 20; + private static final int __POPULATE_IO_CACHE_ON_FLUSH_ISSET_ID = 21; private static final int __INDEX_INTERVAL_ISSET_ID = 22; private int __isset_bitfield = 0; - private _Fields optionals[] = {_Fields.COLUMN_TYPE,_Fields.COMPARATOR_TYPE,_Fields.SUBCOMPARATOR_TYPE,_Fields.COMMENT,_Fields.READ_REPAIR_CHANCE,_Fields.COLUMN_METADATA,_Fields.GC_GRACE_SECONDS,_Fields.DEFAULT_VALIDATION_CLASS,_Fields.ID,_Fields.MIN_COMPACTION_THRESHOLD,_Fields.MAX_COMPACTION_THRESHOLD,_Fields.KEY_VALIDATION_CLASS,_Fields.KEY_ALIAS,_Fields.COMPACTION_STRATEGY,_Fields.COMPACTION_STRATEGY_OPTIONS,_Fields.COMPRESSION_OPTIONS,_Fields.BLOOM_FILTER_FP_CHANCE,_Fields.CACHING,_Fields.DCLOCAL_READ_REPAIR_CHANCE,_Fields.POPULATE_IO_CACHE_ON_FLUSH,_Fields.MEMTABLE_FLUSH_PERIOD_IN_MS,_Fields.DEFAULT_TIME_TO_LIVE,_Fields.SPECULATIVE_RETRY,_Fields.TRIGGERS,_Fields.CELLS_PER_ROW_TO_CACHE,_Fields.MIN_INDEX_INTERVAL,_Fields.MAX_INDEX_INTERVAL,_Fields.ROW_CACHE_SIZE,_Fields.KEY_CACHE_SIZE,_Fields.ROW_CACHE_SAVE_PERIOD_IN_SECONDS,_Fields.KEY_CACHE_SAVE_PERIOD_IN_SECONDS,_Fields.MEMTABLE_FLUSH_AFTER_MINS,_Fields.MEMTABLE_THROUGHPUT_IN_MB,_Fields.MEMTABLE_OPERATIONS_IN_MILLIONS,_Fields.REPLICATE_ON_WRITE,_Fields.MERGE_SHARDS_CHANCE,_Fields.ROW_CACHE_PROVIDER,_Fields.ROW_CACHE_KEYS_TO_SAVE,_Fields.INDEX_INTERVAL}; + private _Fields optionals[] = {_Fields.COLUMN_TYPE,_Fields.COMPARATOR_TYPE,_Fields.SUBCOMPARATOR_TYPE,_Fields.COMMENT,_Fields.READ_REPAIR_CHANCE,_Fields.COLUMN_METADATA,_Fields.GC_GRACE_SECONDS,_Fields.DEFAULT_VALIDATION_CLASS,_Fields.ID,_Fields.MIN_COMPACTION_THRESHOLD,_Fields.MAX_COMPACTION_THRESHOLD,_Fields.KEY_VALIDATION_CLASS,_Fields.KEY_ALIAS,_Fields.COMPACTION_STRATEGY,_Fields.COMPACTION_STRATEGY_OPTIONS,_Fields.COMPRESSION_OPTIONS,_Fields.BLOOM_FILTER_FP_CHANCE,_Fields.CACHING,_Fields.DCLOCAL_READ_REPAIR_CHANCE,_Fields.MEMTABLE_FLUSH_PERIOD_IN_MS,_Fields.DEFAULT_TIME_TO_LIVE,_Fields.SPECULATIVE_RETRY,_Fields.TRIGGERS,_Fields.CELLS_PER_ROW_TO_CACHE,_Fields.MIN_INDEX_INTERVAL,_Fields.MAX_INDEX_INTERVAL,_Fields.ROW_CACHE_SIZE,_Fields.KEY_CACHE_SIZE,_Fields.ROW_CACHE_SAVE_PERIOD_IN_SECONDS,_Fields.KEY_CACHE_SAVE_PERIOD_IN_SECONDS,_Fields.MEMTABLE_FLUSH_AFTER_MINS,_Fields.MEMTABLE_THROUGHPUT_IN_MB,_Fields.MEMTABLE_OPERATIONS_IN_MILLIONS,_Fields.REPLICATE_ON_WRITE,_Fields.MERGE_SHARDS_CHANCE,_Fields.ROW_CACHE_PROVIDER,_Fields.ROW_CACHE_KEYS_TO_SAVE,_Fields.POPULATE_IO_CACHE_ON_FLUSH,_Fields.INDEX_INTERVAL}; public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; static { Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); @@ -473,8 +479,6 @@ public class CfDef implements org.apache.thrift.TBase, jav new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); tmpMap.put(_Fields.DCLOCAL_READ_REPAIR_CHANCE, new org.apache.thrift.meta_data.FieldMetaData("dclocal_read_repair_chance", org.apache.thrift.TFieldRequirementType.OPTIONAL, new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.DOUBLE))); - tmpMap.put(_Fields.POPULATE_IO_CACHE_ON_FLUSH, new org.apache.thrift.meta_data.FieldMetaData("populate_io_cache_on_flush", org.apache.thrift.TFieldRequirementType.OPTIONAL, - new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.BOOL))); tmpMap.put(_Fields.MEMTABLE_FLUSH_PERIOD_IN_MS, new org.apache.thrift.meta_data.FieldMetaData("memtable_flush_period_in_ms", org.apache.thrift.TFieldRequirementType.OPTIONAL, new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32))); tmpMap.put(_Fields.DEFAULT_TIME_TO_LIVE, new org.apache.thrift.meta_data.FieldMetaData("default_time_to_live", org.apache.thrift.TFieldRequirementType.OPTIONAL, @@ -512,6 +516,8 @@ public class CfDef implements org.apache.thrift.TBase, jav new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); tmpMap.put(_Fields.ROW_CACHE_KEYS_TO_SAVE, new org.apache.thrift.meta_data.FieldMetaData("row_cache_keys_to_save", org.apache.thrift.TFieldRequirementType.OPTIONAL, new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32))); + tmpMap.put(_Fields.POPULATE_IO_CACHE_ON_FLUSH, new org.apache.thrift.meta_data.FieldMetaData("populate_io_cache_on_flush", org.apache.thrift.TFieldRequirementType.OPTIONAL, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.BOOL))); tmpMap.put(_Fields.INDEX_INTERVAL, new org.apache.thrift.meta_data.FieldMetaData("index_interval", org.apache.thrift.TFieldRequirementType.OPTIONAL, new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32))); metaDataMap = Collections.unmodifiableMap(tmpMap); @@ -603,7 +609,6 @@ public class CfDef implements org.apache.thrift.TBase, jav this.caching = other.caching; } this.dclocal_read_repair_chance = other.dclocal_read_repair_chance; - this.populate_io_cache_on_flush = other.populate_io_cache_on_flush; this.memtable_flush_period_in_ms = other.memtable_flush_period_in_ms; this.default_time_to_live = other.default_time_to_live; if (other.isSetSpeculative_retry()) { @@ -634,6 +639,7 @@ public class CfDef implements org.apache.thrift.TBase, jav this.row_cache_provider = other.row_cache_provider; } this.row_cache_keys_to_save = other.row_cache_keys_to_save; + this.populate_io_cache_on_flush = other.populate_io_cache_on_flush; this.index_interval = other.index_interval; } @@ -674,8 +680,6 @@ public class CfDef implements org.apache.thrift.TBase, jav this.dclocal_read_repair_chance = 0; - setPopulate_io_cache_on_flushIsSet(false); - this.populate_io_cache_on_flush = false; setMemtable_flush_period_in_msIsSet(false); this.memtable_flush_period_in_ms = 0; setDefault_time_to_liveIsSet(false); @@ -710,6 +714,8 @@ public class CfDef implements org.apache.thrift.TBase, jav this.row_cache_provider = null; setRow_cache_keys_to_saveIsSet(false); this.row_cache_keys_to_save = 0; + setPopulate_io_cache_on_flushIsSet(false); + this.populate_io_cache_on_flush = false; setIndex_intervalIsSet(false); this.index_interval = 0; } @@ -1258,29 +1264,6 @@ public class CfDef implements org.apache.thrift.TBase, jav __isset_bitfield = EncodingUtils.setBit(__isset_bitfield, __DCLOCAL_READ_REPAIR_CHANCE_ISSET_ID, value); } - public boolean isPopulate_io_cache_on_flush() { - return this.populate_io_cache_on_flush; - } - - public CfDef setPopulate_io_cache_on_flush(boolean populate_io_cache_on_flush) { - this.populate_io_cache_on_flush = populate_io_cache_on_flush; - setPopulate_io_cache_on_flushIsSet(true); - return this; - } - - public void unsetPopulate_io_cache_on_flush() { - __isset_bitfield = EncodingUtils.clearBit(__isset_bitfield, __POPULATE_IO_CACHE_ON_FLUSH_ISSET_ID); - } - - /** Returns true if field populate_io_cache_on_flush is set (has been assigned a value) and false otherwise */ - public boolean isSetPopulate_io_cache_on_flush() { - return EncodingUtils.testBit(__isset_bitfield, __POPULATE_IO_CACHE_ON_FLUSH_ISSET_ID); - } - - public void setPopulate_io_cache_on_flushIsSet(boolean value) { - __isset_bitfield = EncodingUtils.setBit(__isset_bitfield, __POPULATE_IO_CACHE_ON_FLUSH_ISSET_ID, value); - } - public int getMemtable_flush_period_in_ms() { return this.memtable_flush_period_in_ms; } @@ -1780,6 +1763,35 @@ public class CfDef implements org.apache.thrift.TBase, jav __isset_bitfield = EncodingUtils.setBit(__isset_bitfield, __ROW_CACHE_KEYS_TO_SAVE_ISSET_ID, value); } + /** + * @deprecated + */ + public boolean isPopulate_io_cache_on_flush() { + return this.populate_io_cache_on_flush; + } + + /** + * @deprecated + */ + public CfDef setPopulate_io_cache_on_flush(boolean populate_io_cache_on_flush) { + this.populate_io_cache_on_flush = populate_io_cache_on_flush; + setPopulate_io_cache_on_flushIsSet(true); + return this; + } + + public void unsetPopulate_io_cache_on_flush() { + __isset_bitfield = EncodingUtils.clearBit(__isset_bitfield, __POPULATE_IO_CACHE_ON_FLUSH_ISSET_ID); + } + + /** Returns true if field populate_io_cache_on_flush is set (has been assigned a value) and false otherwise */ + public boolean isSetPopulate_io_cache_on_flush() { + return EncodingUtils.testBit(__isset_bitfield, __POPULATE_IO_CACHE_ON_FLUSH_ISSET_ID); + } + + public void setPopulate_io_cache_on_flushIsSet(boolean value) { + __isset_bitfield = EncodingUtils.setBit(__isset_bitfield, __POPULATE_IO_CACHE_ON_FLUSH_ISSET_ID, value); + } + /** * @deprecated */ @@ -1979,14 +1991,6 @@ public class CfDef implements org.apache.thrift.TBase, jav } break; - case POPULATE_IO_CACHE_ON_FLUSH: - if (value == null) { - unsetPopulate_io_cache_on_flush(); - } else { - setPopulate_io_cache_on_flush((Boolean)value); - } - break; - case MEMTABLE_FLUSH_PERIOD_IN_MS: if (value == null) { unsetMemtable_flush_period_in_ms(); @@ -2131,6 +2135,14 @@ public class CfDef implements org.apache.thrift.TBase, jav } break; + case POPULATE_IO_CACHE_ON_FLUSH: + if (value == null) { + unsetPopulate_io_cache_on_flush(); + } else { + setPopulate_io_cache_on_flush((Boolean)value); + } + break; + case INDEX_INTERVAL: if (value == null) { unsetIndex_interval(); @@ -2207,9 +2219,6 @@ public class CfDef implements org.apache.thrift.TBase, jav case DCLOCAL_READ_REPAIR_CHANCE: return Double.valueOf(getDclocal_read_repair_chance()); - case POPULATE_IO_CACHE_ON_FLUSH: - return Boolean.valueOf(isPopulate_io_cache_on_flush()); - case MEMTABLE_FLUSH_PERIOD_IN_MS: return Integer.valueOf(getMemtable_flush_period_in_ms()); @@ -2264,6 +2273,9 @@ public class CfDef implements org.apache.thrift.TBase, jav case ROW_CACHE_KEYS_TO_SAVE: return Integer.valueOf(getRow_cache_keys_to_save()); + case POPULATE_IO_CACHE_ON_FLUSH: + return Boolean.valueOf(isPopulate_io_cache_on_flush()); + case INDEX_INTERVAL: return Integer.valueOf(getIndex_interval()); @@ -2320,8 +2332,6 @@ public class CfDef implements org.apache.thrift.TBase, jav return isSetCaching(); case DCLOCAL_READ_REPAIR_CHANCE: return isSetDclocal_read_repair_chance(); - case POPULATE_IO_CACHE_ON_FLUSH: - return isSetPopulate_io_cache_on_flush(); case MEMTABLE_FLUSH_PERIOD_IN_MS: return isSetMemtable_flush_period_in_ms(); case DEFAULT_TIME_TO_LIVE: @@ -2358,6 +2368,8 @@ public class CfDef implements org.apache.thrift.TBase, jav return isSetRow_cache_provider(); case ROW_CACHE_KEYS_TO_SAVE: return isSetRow_cache_keys_to_save(); + case POPULATE_IO_CACHE_ON_FLUSH: + return isSetPopulate_io_cache_on_flush(); case INDEX_INTERVAL: return isSetIndex_interval(); } @@ -2566,15 +2578,6 @@ public class CfDef implements org.apache.thrift.TBase, jav return false; } - boolean this_present_populate_io_cache_on_flush = true && this.isSetPopulate_io_cache_on_flush(); - boolean that_present_populate_io_cache_on_flush = true && that.isSetPopulate_io_cache_on_flush(); - if (this_present_populate_io_cache_on_flush || that_present_populate_io_cache_on_flush) { - if (!(this_present_populate_io_cache_on_flush && that_present_populate_io_cache_on_flush)) - return false; - if (this.populate_io_cache_on_flush != that.populate_io_cache_on_flush) - return false; - } - boolean this_present_memtable_flush_period_in_ms = true && this.isSetMemtable_flush_period_in_ms(); boolean that_present_memtable_flush_period_in_ms = true && that.isSetMemtable_flush_period_in_ms(); if (this_present_memtable_flush_period_in_ms || that_present_memtable_flush_period_in_ms) { @@ -2737,6 +2740,15 @@ public class CfDef implements org.apache.thrift.TBase, jav return false; } + boolean this_present_populate_io_cache_on_flush = true && this.isSetPopulate_io_cache_on_flush(); + boolean that_present_populate_io_cache_on_flush = true && that.isSetPopulate_io_cache_on_flush(); + if (this_present_populate_io_cache_on_flush || that_present_populate_io_cache_on_flush) { + if (!(this_present_populate_io_cache_on_flush && that_present_populate_io_cache_on_flush)) + return false; + if (this.populate_io_cache_on_flush != that.populate_io_cache_on_flush) + return false; + } + boolean this_present_index_interval = true && this.isSetIndex_interval(); boolean that_present_index_interval = true && that.isSetIndex_interval(); if (this_present_index_interval || that_present_index_interval) { @@ -2858,11 +2870,6 @@ public class CfDef implements org.apache.thrift.TBase, jav if (present_dclocal_read_repair_chance) builder.append(dclocal_read_repair_chance); - boolean present_populate_io_cache_on_flush = true && (isSetPopulate_io_cache_on_flush()); - builder.append(present_populate_io_cache_on_flush); - if (present_populate_io_cache_on_flush) - builder.append(populate_io_cache_on_flush); - boolean present_memtable_flush_period_in_ms = true && (isSetMemtable_flush_period_in_ms()); builder.append(present_memtable_flush_period_in_ms); if (present_memtable_flush_period_in_ms) @@ -2953,6 +2960,11 @@ public class CfDef implements org.apache.thrift.TBase, jav if (present_row_cache_keys_to_save) builder.append(row_cache_keys_to_save); + boolean present_populate_io_cache_on_flush = true && (isSetPopulate_io_cache_on_flush()); + builder.append(present_populate_io_cache_on_flush); + if (present_populate_io_cache_on_flush) + builder.append(populate_io_cache_on_flush); + boolean present_index_interval = true && (isSetIndex_interval()); builder.append(present_index_interval); if (present_index_interval) @@ -3179,16 +3191,6 @@ public class CfDef implements org.apache.thrift.TBase, jav return lastComparison; } } - lastComparison = Boolean.valueOf(isSetPopulate_io_cache_on_flush()).compareTo(other.isSetPopulate_io_cache_on_flush()); - if (lastComparison != 0) { - return lastComparison; - } - if (isSetPopulate_io_cache_on_flush()) { - lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.populate_io_cache_on_flush, other.populate_io_cache_on_flush); - if (lastComparison != 0) { - return lastComparison; - } - } lastComparison = Boolean.valueOf(isSetMemtable_flush_period_in_ms()).compareTo(other.isSetMemtable_flush_period_in_ms()); if (lastComparison != 0) { return lastComparison; @@ -3369,6 +3371,16 @@ public class CfDef implements org.apache.thrift.TBase, jav return lastComparison; } } + lastComparison = Boolean.valueOf(isSetPopulate_io_cache_on_flush()).compareTo(other.isSetPopulate_io_cache_on_flush()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetPopulate_io_cache_on_flush()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.populate_io_cache_on_flush, other.populate_io_cache_on_flush); + if (lastComparison != 0) { + return lastComparison; + } + } lastComparison = Boolean.valueOf(isSetIndex_interval()).compareTo(other.isSetIndex_interval()); if (lastComparison != 0) { return lastComparison; @@ -3576,12 +3588,6 @@ public class CfDef implements org.apache.thrift.TBase, jav sb.append(this.dclocal_read_repair_chance); first = false; } - if (isSetPopulate_io_cache_on_flush()) { - if (!first) sb.append(", "); - sb.append("populate_io_cache_on_flush:"); - sb.append(this.populate_io_cache_on_flush); - first = false; - } if (isSetMemtable_flush_period_in_ms()) { if (!first) sb.append(", "); sb.append("memtable_flush_period_in_ms:"); @@ -3706,6 +3712,12 @@ public class CfDef implements org.apache.thrift.TBase, jav sb.append(this.row_cache_keys_to_save); first = false; } + if (isSetPopulate_io_cache_on_flush()) { + if (!first) sb.append(", "); + sb.append("populate_io_cache_on_flush:"); + sb.append(this.populate_io_cache_on_flush); + first = false; + } if (isSetIndex_interval()) { if (!first) sb.append(", "); sb.append("index_interval:"); @@ -3966,14 +3978,6 @@ public class CfDef implements org.apache.thrift.TBase, jav org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); } break; - case 38: // POPULATE_IO_CACHE_ON_FLUSH - if (schemeField.type == org.apache.thrift.protocol.TType.BOOL) { - struct.populate_io_cache_on_flush = iprot.readBool(); - struct.setPopulate_io_cache_on_flushIsSet(true); - } else { - org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); - } - break; case 39: // MEMTABLE_FLUSH_PERIOD_IN_MS if (schemeField.type == org.apache.thrift.protocol.TType.I32) { struct.memtable_flush_period_in_ms = iprot.readI32(); @@ -4129,6 +4133,14 @@ public class CfDef implements org.apache.thrift.TBase, jav org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); } break; + case 38: // POPULATE_IO_CACHE_ON_FLUSH + if (schemeField.type == org.apache.thrift.protocol.TType.BOOL) { + struct.populate_io_cache_on_flush = iprot.readBool(); + struct.setPopulate_io_cache_on_flushIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; case 41: // INDEX_INTERVAL if (schemeField.type == org.apache.thrift.protocol.TType.I32) { struct.index_interval = iprot.readI32(); @@ -4496,61 +4508,61 @@ public class CfDef implements org.apache.thrift.TBase, jav if (struct.isSetDclocal_read_repair_chance()) { optionals.set(18); } - if (struct.isSetPopulate_io_cache_on_flush()) { + if (struct.isSetMemtable_flush_period_in_ms()) { optionals.set(19); } - if (struct.isSetMemtable_flush_period_in_ms()) { + if (struct.isSetDefault_time_to_live()) { optionals.set(20); } - if (struct.isSetDefault_time_to_live()) { + if (struct.isSetSpeculative_retry()) { optionals.set(21); } - if (struct.isSetSpeculative_retry()) { + if (struct.isSetTriggers()) { optionals.set(22); } - if (struct.isSetTriggers()) { + if (struct.isSetCells_per_row_to_cache()) { optionals.set(23); } - if (struct.isSetCells_per_row_to_cache()) { + if (struct.isSetMin_index_interval()) { optionals.set(24); } - if (struct.isSetMin_index_interval()) { + if (struct.isSetMax_index_interval()) { optionals.set(25); } - if (struct.isSetMax_index_interval()) { + if (struct.isSetRow_cache_size()) { optionals.set(26); } - if (struct.isSetRow_cache_size()) { + if (struct.isSetKey_cache_size()) { optionals.set(27); } - if (struct.isSetKey_cache_size()) { + if (struct.isSetRow_cache_save_period_in_seconds()) { optionals.set(28); } - if (struct.isSetRow_cache_save_period_in_seconds()) { + if (struct.isSetKey_cache_save_period_in_seconds()) { optionals.set(29); } - if (struct.isSetKey_cache_save_period_in_seconds()) { + if (struct.isSetMemtable_flush_after_mins()) { optionals.set(30); } - if (struct.isSetMemtable_flush_after_mins()) { + if (struct.isSetMemtable_throughput_in_mb()) { optionals.set(31); } - if (struct.isSetMemtable_throughput_in_mb()) { + if (struct.isSetMemtable_operations_in_millions()) { optionals.set(32); } - if (struct.isSetMemtable_operations_in_millions()) { + if (struct.isSetReplicate_on_write()) { optionals.set(33); } - if (struct.isSetReplicate_on_write()) { + if (struct.isSetMerge_shards_chance()) { optionals.set(34); } - if (struct.isSetMerge_shards_chance()) { + if (struct.isSetRow_cache_provider()) { optionals.set(35); } - if (struct.isSetRow_cache_provider()) { + if (struct.isSetRow_cache_keys_to_save()) { optionals.set(36); } - if (struct.isSetRow_cache_keys_to_save()) { + if (struct.isSetPopulate_io_cache_on_flush()) { optionals.set(37); } if (struct.isSetIndex_interval()) { @@ -4634,9 +4646,6 @@ public class CfDef implements org.apache.thrift.TBase, jav if (struct.isSetDclocal_read_repair_chance()) { oprot.writeDouble(struct.dclocal_read_repair_chance); } - if (struct.isSetPopulate_io_cache_on_flush()) { - oprot.writeBool(struct.populate_io_cache_on_flush); - } if (struct.isSetMemtable_flush_period_in_ms()) { oprot.writeI32(struct.memtable_flush_period_in_ms); } @@ -4697,6 +4706,9 @@ public class CfDef implements org.apache.thrift.TBase, jav if (struct.isSetRow_cache_keys_to_save()) { oprot.writeI32(struct.row_cache_keys_to_save); } + if (struct.isSetPopulate_io_cache_on_flush()) { + oprot.writeBool(struct.populate_io_cache_on_flush); + } if (struct.isSetIndex_interval()) { oprot.writeI32(struct.index_interval); } @@ -4819,22 +4831,18 @@ public class CfDef implements org.apache.thrift.TBase, jav struct.setDclocal_read_repair_chanceIsSet(true); } if (incoming.get(19)) { - struct.populate_io_cache_on_flush = iprot.readBool(); - struct.setPopulate_io_cache_on_flushIsSet(true); - } - if (incoming.get(20)) { struct.memtable_flush_period_in_ms = iprot.readI32(); struct.setMemtable_flush_period_in_msIsSet(true); } - if (incoming.get(21)) { + if (incoming.get(20)) { struct.default_time_to_live = iprot.readI32(); struct.setDefault_time_to_liveIsSet(true); } - if (incoming.get(22)) { + if (incoming.get(21)) { struct.speculative_retry = iprot.readString(); struct.setSpeculative_retryIsSet(true); } - if (incoming.get(23)) { + if (incoming.get(22)) { { org.apache.thrift.protocol.TList _list143 = new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRUCT, iprot.readI32()); struct.triggers = new ArrayList(_list143.size); @@ -4848,62 +4856,66 @@ public class CfDef implements org.apache.thrift.TBase, jav } struct.setTriggersIsSet(true); } - if (incoming.get(24)) { + if (incoming.get(23)) { struct.cells_per_row_to_cache = iprot.readString(); struct.setCells_per_row_to_cacheIsSet(true); } - if (incoming.get(25)) { + if (incoming.get(24)) { struct.min_index_interval = iprot.readI32(); struct.setMin_index_intervalIsSet(true); } - if (incoming.get(26)) { + if (incoming.get(25)) { struct.max_index_interval = iprot.readI32(); struct.setMax_index_intervalIsSet(true); } - if (incoming.get(27)) { + if (incoming.get(26)) { struct.row_cache_size = iprot.readDouble(); struct.setRow_cache_sizeIsSet(true); } - if (incoming.get(28)) { + if (incoming.get(27)) { struct.key_cache_size = iprot.readDouble(); struct.setKey_cache_sizeIsSet(true); } - if (incoming.get(29)) { + if (incoming.get(28)) { struct.row_cache_save_period_in_seconds = iprot.readI32(); struct.setRow_cache_save_period_in_secondsIsSet(true); } - if (incoming.get(30)) { + if (incoming.get(29)) { struct.key_cache_save_period_in_seconds = iprot.readI32(); struct.setKey_cache_save_period_in_secondsIsSet(true); } - if (incoming.get(31)) { + if (incoming.get(30)) { struct.memtable_flush_after_mins = iprot.readI32(); struct.setMemtable_flush_after_minsIsSet(true); } - if (incoming.get(32)) { + if (incoming.get(31)) { struct.memtable_throughput_in_mb = iprot.readI32(); struct.setMemtable_throughput_in_mbIsSet(true); } - if (incoming.get(33)) { + if (incoming.get(32)) { struct.memtable_operations_in_millions = iprot.readDouble(); struct.setMemtable_operations_in_millionsIsSet(true); } - if (incoming.get(34)) { + if (incoming.get(33)) { struct.replicate_on_write = iprot.readBool(); struct.setReplicate_on_writeIsSet(true); } - if (incoming.get(35)) { + if (incoming.get(34)) { struct.merge_shards_chance = iprot.readDouble(); struct.setMerge_shards_chanceIsSet(true); } - if (incoming.get(36)) { + if (incoming.get(35)) { struct.row_cache_provider = iprot.readString(); struct.setRow_cache_providerIsSet(true); } - if (incoming.get(37)) { + if (incoming.get(36)) { struct.row_cache_keys_to_save = iprot.readI32(); struct.setRow_cache_keys_to_saveIsSet(true); } + if (incoming.get(37)) { + struct.populate_io_cache_on_flush = iprot.readBool(); + struct.setPopulate_io_cache_on_flushIsSet(true); + } if (incoming.get(38)) { struct.index_interval = iprot.readI32(); struct.setIndex_intervalIsSet(true); diff --git a/interface/thrift/gen-java/org/apache/cassandra/thrift/CqlRow.java b/interface/thrift/gen-java/org/apache/cassandra/thrift/CqlRow.java index bc0cf77ae5..7487ed7203 100644 --- a/interface/thrift/gen-java/org/apache/cassandra/thrift/CqlRow.java +++ b/interface/thrift/gen-java/org/apache/cassandra/thrift/CqlRow.java @@ -55,7 +55,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Row returned from a CQL query + * Row returned from a CQL query. + * + * This struct is used for both CQL2 and CQL3 queries. For CQL2, the partition key + * is special-cased and is always returned. For CQL3, it is not special cased; + * it will be included in the columns list if it was included in the SELECT and + * the key field is always null. */ public class CqlRow implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("CqlRow"); diff --git a/src/java/org/apache/cassandra/cql3/statements/CQL3CasConditions.java b/src/java/org/apache/cassandra/cql3/statements/CQL3CasConditions.java index 8e1f5acdd5..39c14f5c5f 100644 --- a/src/java/org/apache/cassandra/cql3/statements/CQL3CasConditions.java +++ b/src/java/org/apache/cassandra/cql3/statements/CQL3CasConditions.java @@ -98,6 +98,7 @@ public class CQL3CasConditions implements CASConditions slices[i++] = prefix.slice(); int toGroup = cfm.comparator.isDense() ? -1 : cfm.clusteringColumns().size(); + assert ColumnSlice.validateSlices(slices, cfm.comparator, false); return new SliceQueryFilter(slices, false, slices.length, toGroup); } diff --git a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java index 501ef45140..d484c5fb1f 100644 --- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java @@ -533,6 +533,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache private SliceQueryFilter sliceFilter(ColumnSlice[] slices, int limit, int toGroup) { + assert ColumnSlice.validateSlices(slices, cfm.comparator, isReversed) : String.format("Invalid slices: " + Arrays.toString(slices) + (isReversed ? " (reversed)" : "")); return new SliceQueryFilter(slices, isReversed, limit, toGroup); } diff --git a/src/java/org/apache/cassandra/db/composites/AbstractCType.java b/src/java/org/apache/cassandra/db/composites/AbstractCType.java index 0e73397522..e299e42936 100644 --- a/src/java/org/apache/cassandra/db/composites/AbstractCType.java +++ b/src/java/org/apache/cassandra/db/composites/AbstractCType.java @@ -60,6 +60,11 @@ public abstract class AbstractCType implements CType { public int compare(Composite c1, Composite c2) { + if (c1.isEmpty()) + return c2.isEmpty() ? 0 : -1; + if (c2.isEmpty()) + return 1; + return AbstractCType.this.compare(c2, c1); } }; diff --git a/src/java/org/apache/cassandra/db/filter/ColumnSlice.java b/src/java/org/apache/cassandra/db/filter/ColumnSlice.java index a9451146e3..bca4743d24 100644 --- a/src/java/org/apache/cassandra/db/filter/ColumnSlice.java +++ b/src/java/org/apache/cassandra/db/filter/ColumnSlice.java @@ -19,6 +19,8 @@ package org.apache.cassandra.db.filter; import java.io.*; import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Comparator; import java.util.List; @@ -108,6 +110,101 @@ public class ColumnSlice return 0; } + /** + * Validates that the provided slice array contains only non-overlapped slices valid for a query {@code reversed} + * or not on a table using {@code comparator}. + */ + public static boolean validateSlices(ColumnSlice[] slices, CellNameType comparator, boolean reversed) + { + return validateSlices(slices, reversed ? comparator.reverseComparator() : comparator); + } + + /** + * Validates that the provided slice array contains only non-overlapped slices in {@code comparator} order. + */ + public static boolean validateSlices(ColumnSlice[] slices, Comparator comparator) + { + for (int i = 0; i < slices.length; i++) + { + if (i > 0 && comparator.compare(slices[i-1].finish, slices[i].start) >= 0) + return false; + + if (slices[i].finish.isEmpty()) + return i == slices.length - 1; + + if (comparator.compare(slices[i].start, slices[i].finish) > 0) + return false; + } + return true; + } + + /** + * Takes an array of slices (potentially overlapping and in any order, though each individual slice must have + * its start before or equal its end in {@code comparator} orde) and return an equivalent array of non-overlapping + * slices in {@code comparator order}. + * + * @param slices an array of slices. This may be modified by this method. + * @param comparator the order in which to sort the slices. + * @return the smallest possible array of non-overlapping slices in {@code compator} order. If the original + * slices are already non-overlapping and in comparator order, this may or may not return the provided slices + * directly. + */ + public static ColumnSlice[] deoverlapSlices(ColumnSlice[] slices, final Comparator comparator) + { + if (slices.length <= 1) + return slices; + + Arrays.sort(slices, new Comparator() + { + @Override + public int compare(ColumnSlice s1, ColumnSlice s2) + { + int c = comparator.compare(s1.start, s2.start); + if (c != 0) + return c; + + // For the finish, empty always means greater + return s1.finish.isEmpty() || s2.finish.isEmpty() + ? s1.finish.isEmpty() ? 1 : s2.finish.isEmpty() ? -1 : 0 + : comparator.compare(s1.finish, s2.finish); + } + }); + + List slicesCopy = new ArrayList<>(slices.length); + + ColumnSlice last = slices[0]; + + for (int i = 1; i < slices.length; i++) + { + ColumnSlice s2 = slices[i]; + + boolean includesStart = last.includes(comparator, s2.start); + boolean includesFinish = s2.finish.isEmpty() ? last.finish.isEmpty() : last.includes(comparator, s2.finish); + + if (includesStart && includesFinish) + continue; + + if (!includesStart && !includesFinish) + { + slicesCopy.add(last); + last = s2; + continue; + } + + if (includesStart) + { + last = new ColumnSlice(last.start, s2.finish); + continue; + } + + assert !includesFinish; + } + + slicesCopy.add(last); + + return slicesCopy.toArray(new ColumnSlice[slicesCopy.size()]); + } + @Override public final int hashCode() { diff --git a/src/java/org/apache/cassandra/thrift/CassandraServer.java b/src/java/org/apache/cassandra/thrift/CassandraServer.java index 4f54242a1c..868c701d1b 100644 --- a/src/java/org/apache/cassandra/thrift/CassandraServer.java +++ b/src/java/org/apache/cassandra/thrift/CassandraServer.java @@ -2031,7 +2031,7 @@ public class CassandraServer implements Cassandra.Iface org.apache.cassandra.db.ConsistencyLevel consistencyLevel = ThriftConversion.fromThrift(request.getConsistency_level()); consistencyLevel.validateForRead(keyspace); List commands = new ArrayList<>(1); - ColumnSlice [] slices = new ColumnSlice[request.getColumn_slices().size()]; + ColumnSlice[] slices = new ColumnSlice[request.getColumn_slices().size()]; for (int i = 0 ; i < request.getColumn_slices().size() ; i++) { fixOptionalSliceParameters(request.getColumn_slices().get(i)); @@ -2044,7 +2044,8 @@ public class CassandraServer implements Cassandra.Iface throw new InvalidRequestException(String.format("Reversed column slice at index %d had start less than finish", i)); slices[i] = new ColumnSlice(start, finish); } - SliceQueryFilter filter = new SliceQueryFilter(slices, request.reversed, request.count); + ColumnSlice[] deoverlapped = ColumnSlice.deoverlapSlices(slices, request.reversed ? metadata.comparator.reverseComparator() : metadata.comparator); + SliceQueryFilter filter = new SliceQueryFilter(deoverlapped, request.reversed, request.count); ThriftValidation.validateKey(metadata, request.key); commands.add(ReadCommand.create(keyspace, request.key, request.column_parent.getColumn_family(), System.currentTimeMillis(), filter)); return getSlice(commands, request.column_parent.isSetSuper_column(), consistencyLevel).entrySet().iterator().next().getValue(); diff --git a/test/unit/org/apache/cassandra/db/filter/ColumnSliceTest.java b/test/unit/org/apache/cassandra/db/filter/ColumnSliceTest.java index 6553de55b7..2dc37441a4 100644 --- a/test/unit/org/apache/cassandra/db/filter/ColumnSliceTest.java +++ b/test/unit/org/apache/cassandra/db/filter/ColumnSliceTest.java @@ -18,22 +18,23 @@ * */ package org.apache.cassandra.db.filter; -import org.apache.cassandra.db.composites.Composite; -import org.apache.cassandra.db.composites.CompoundDenseCellNameType; + +import java.nio.ByteBuffer; +import java.util.*; + +import org.junit.Test; + +import org.apache.cassandra.db.composites.*; import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.db.marshal.Int32Type; import org.apache.cassandra.utils.ByteBufferUtil; -import org.junit.Test; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; public class ColumnSliceTest { + private static final CellNameType simpleIntType = new SimpleDenseCellNameType(Int32Type.instance); + @Test public void testIntersectsSingleSlice() { @@ -278,6 +279,65 @@ public class ColumnSliceTest assertTrue(slice.intersects(columnNames(1, 0, 0), columnNames(2, 2, 2), nameType, true)); } + @Test + public void testDeoverlapSlices() + { + ColumnSlice[] slices; + ColumnSlice[] deoverlapped; + + // Preserve correct slices + slices = slices(s(0, 3), s(4, 5), s(6, 9)); + assertSlicesValid(slices); + assertSlicesEquals(slices, deoverlapSlices(slices)); + + // Simple overlap + slices = slices(s(0, 3), s(2, 5), s(8, 9)); + assertSlicesInvalid(slices); + assertSlicesEquals(slices(s(0, 5), s(8, 9)), deoverlapSlices(slices)); + + // Slice overlaps others fully + slices = slices(s(0, 10), s(2, 5), s(8, 9)); + assertSlicesInvalid(slices); + assertSlicesEquals(slices(s(0, 10)), deoverlapSlices(slices)); + + // Slice with empty end overlaps others fully + slices = slices(s(0, -1), s(2, 5), s(8, 9)); + assertSlicesInvalid(slices); + assertSlicesEquals(slices(s(0, -1)), deoverlapSlices(slices)); + + // Overlap with slices selecting only one element + slices = slices(s(0, 4), s(4, 4), s(4, 8)); + assertSlicesInvalid(slices); + assertSlicesEquals(slices(s(0, 8)), deoverlapSlices(slices)); + + // Unordered slices (without overlap) + slices = slices(s(4, 8), s(0, 3), s(9, 9)); + assertSlicesInvalid(slices); + assertSlicesEquals(slices(s(0, 3), s(4, 8), s(9, 9)), deoverlapSlices(slices)); + + // All range select but not by a single slice + slices = slices(s(5, -1), s(2, 5), s(-1, 2)); + assertSlicesInvalid(slices); + assertSlicesEquals(slices(s(-1, -1)), deoverlapSlices(slices)); + } + + @Test + public void testValidateSlices() + { + assertSlicesValid(slices(s(0, 3))); + assertSlicesValid(slices(s(3, 3))); + assertSlicesValid(slices(s(3, 3), s(4, 4))); + assertSlicesValid(slices(s(0, 3), s(4, 5), s(6, 9))); + assertSlicesValid(slices(s(-1, -1))); + assertSlicesValid(slices(s(-1, 3), s(4, -1))); + + assertSlicesInvalid(slices(s(3, 0))); + assertSlicesInvalid(slices(s(0, 2), s(2, 4))); + assertSlicesInvalid(slices(s(0, 2), s(1, 4))); + assertSlicesInvalid(slices(s(0, 2), s(3, 4), s(3, 4))); + assertSlicesInvalid(slices(s(-1, 2), s(3, -1), s(5, 9))); + } + private static Composite composite(Integer ... components) { List> types = new ArrayList<>(); @@ -295,4 +355,61 @@ public class ColumnSliceTest names.add(ByteBufferUtil.bytes(component)); return names; } -} \ No newline at end of file + + private static Composite simpleComposite(int i) + { + // We special negative values to mean EMPTY for convenience sake + if (i < 0) + return Composites.EMPTY; + + return simpleIntType.make(i); + } + + private static ColumnSlice s(int start, int finish) + { + return new ColumnSlice(simpleComposite(start), simpleComposite(finish)); + } + + private static ColumnSlice[] slices(ColumnSlice... slices) + { + return slices; + } + + private static ColumnSlice[] deoverlapSlices(ColumnSlice[] slices) + { + return ColumnSlice.deoverlapSlices(slices, simpleIntType); + } + + private static void assertSlicesValid(ColumnSlice[] slices) + { + assertTrue("Slices " + toString(slices) + " should be valid", ColumnSlice.validateSlices(slices, simpleIntType)); + } + + private static void assertSlicesInvalid(ColumnSlice[] slices) + { + assertFalse("Slices " + toString(slices) + " shouldn't be valid", ColumnSlice.validateSlices(slices, simpleIntType)); + } + + private static void assertSlicesEquals(ColumnSlice[] expected, ColumnSlice[] actual) + { + assertTrue("Expected " + toString(expected) + " but got " + toString(actual), Arrays.equals(expected, actual)); + } + + private static String toString(ColumnSlice[] slices) + { + StringBuilder sb = new StringBuilder().append("["); + for (int i = 0; i < slices.length; i++) + { + if (i > 0) + sb.append(", "); + + ColumnSlice slice = slices[i]; + sb.append("("); + sb.append(slice.start.isEmpty() ? "-1" : simpleIntType.getString(slice.start)); + sb.append(", "); + sb.append(slice.finish.isEmpty() ? "-1" : simpleIntType.getString(slice.finish)); + sb.append(")"); + } + return sb.append("]").toString(); + } +} diff --git a/test/unit/org/apache/cassandra/thrift/MultiSliceTest.java b/test/unit/org/apache/cassandra/thrift/MultiSliceTest.java index d1c913bf2b..9193258358 100644 --- a/test/unit/org/apache/cassandra/thrift/MultiSliceTest.java +++ b/test/unit/org/apache/cassandra/thrift/MultiSliceTest.java @@ -114,9 +114,21 @@ public class MultiSliceTest extends SchemaLoader req.setCount(6); req.reversed = true; req.setColumn_slices(Arrays.asList(columnSliceFrom("e", "a"), columnSliceFrom("g", "d"))); - assertColumnNameMatches(Arrays.asList("g", "e", "d", "c", "b", "a"), server.get_multi_slice(req)); + assertColumnNameMatches(Arrays.asList("g", "f", "e", "d", "c", "b"), server.get_multi_slice(req)); } - + + @Test + public void test_with_overlap_with_count() throws TException + { + ColumnParent cp = new ColumnParent("Standard1"); + ByteBuffer key = ByteBuffer.wrap("overlap_reversed_count".getBytes()); + addTheAlphabetToRow(key, cp); + MultiSliceRequest req = makeMultiSliceRequest(key); + req.setCount(6); + req.setColumn_slices(Arrays.asList(columnSliceFrom("a", "e"), columnSliceFrom("d", "g"), columnSliceFrom("d", "g"))); + assertColumnNameMatches(Arrays.asList("a", "b", "c", "d", "e", "f"), server.get_multi_slice(req)); + } + private static void addTheAlphabetToRow(ByteBuffer key, ColumnParent parent) throws InvalidRequestException, UnavailableException, TimedOutException { @@ -135,7 +147,7 @@ public class MultiSliceTest extends SchemaLoader for (int i = 0 ; i< expected.size() ; i++) { Assert.assertEquals(actual.get(i) +" did not equal "+ expected.get(i), - new String(actual.get(i).getColumn().getName()), expected.get(i)); + expected.get(i), new String(actual.get(i).getColumn().getName())); } } @@ -146,4 +158,4 @@ public class MultiSliceTest extends SchemaLoader cs.setFinish(ByteBufferUtil.bytes(endInclusive)); return cs; } -} \ No newline at end of file +}