mirror of https://github.com/apache/cassandra
Adds support for columns that act as incr/decr counters. Patch primarily by Kelvin Kakugawa with select parts from Chris Goffinet, Sylvain Lebresne, Rob Coli, Johan Oskarsson, Adam Samet, Jaakko Laine and more. Review by Jonathan Ellis and Sylvain Lebresne. CASSANDRA-1072.
git-svn-id: https://svn.apache.org/repos/asf/cassandra/trunk@1051679 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
e9b1acc5f4
commit
2c4ac98c9f
|
|
@ -1,5 +1,6 @@
|
|||
0.8-dev
|
||||
* avoid double RowMutation serialization on write path (CASSANDRA-1800)
|
||||
* adds support for columns that act as incr/decr counters (CASSANDRA-1072)
|
||||
|
||||
|
||||
0.7-dev
|
||||
|
|
|
|||
|
|
@ -459,3 +459,10 @@ keyspaces:
|
|||
validator_class: LongType
|
||||
index_name: birthdate_idx
|
||||
index_type: KEYS
|
||||
|
||||
- name: Counter1
|
||||
default_validation_class: CounterColumnType
|
||||
|
||||
- name: SuperCounter1
|
||||
column_type: Super
|
||||
default_validation_class: CounterColumnType
|
||||
|
|
|
|||
|
|
@ -146,6 +146,7 @@ protocol Cassandra {
|
|||
union { double, null } row_cache_size;
|
||||
union { double, null } key_cache_size;
|
||||
union { double, null } read_repair_chance;
|
||||
union { boolean, null } replicate_on_write;
|
||||
union { int, null } gc_grace_seconds;
|
||||
union { null, string } default_validation_class = null;
|
||||
union { null, int } min_compaction_threshold = null;
|
||||
|
|
|
|||
|
|
@ -189,6 +189,21 @@ struct ColumnPath {
|
|||
5: optional binary column,
|
||||
}
|
||||
|
||||
struct CounterColumn {
|
||||
1: required binary name,
|
||||
2: required i64 value
|
||||
}
|
||||
|
||||
struct CounterSuperColumn {
|
||||
1: required binary name,
|
||||
2: required list<CounterColumn> columns
|
||||
}
|
||||
|
||||
struct Counter {
|
||||
1: optional CounterColumn column,
|
||||
2: optional CounterSuperColumn super_column
|
||||
}
|
||||
|
||||
/**
|
||||
A slice range is a structure that stores basic range, ordering and limit information for a query that will return
|
||||
multiple columns. It could be thought of as Cassandra's version of LIMIT and ORDER BY
|
||||
|
|
@ -298,6 +313,21 @@ struct Mutation {
|
|||
2: optional Deletion deletion,
|
||||
}
|
||||
|
||||
struct CounterDeletion {
|
||||
1: optional binary super_column,
|
||||
2: optional SlicePredicate predicate,
|
||||
}
|
||||
|
||||
/**
|
||||
A CounterMutation is either an insert, represented by filling counter, or a deletion, represented by filling the deletion attribute.
|
||||
@param counter. An insert to a counter column or supercolumn
|
||||
@param deletion. A deletion of a counter column or supercolumn
|
||||
*/
|
||||
struct CounterMutation {
|
||||
1: optional Counter counter,
|
||||
2: optional CounterDeletion deletion,
|
||||
}
|
||||
|
||||
struct TokenRange {
|
||||
1: required string start_token,
|
||||
2: required string end_token,
|
||||
|
|
@ -346,6 +376,7 @@ struct CfDef {
|
|||
21: optional i32 memtable_flush_after_mins,
|
||||
22: optional i32 memtable_throughput_in_mb,
|
||||
23: optional double memtable_operations_in_millions,
|
||||
24: optional bool replicate_on_write=0,
|
||||
}
|
||||
|
||||
/* describes a keyspace. */
|
||||
|
|
@ -470,6 +501,59 @@ service Cassandra {
|
|||
*/
|
||||
void truncate(1:required string cfname)
|
||||
throws (1: InvalidRequestException ire, 2: UnavailableException ue),
|
||||
|
||||
|
||||
# counter methods
|
||||
|
||||
/**
|
||||
* Increment or decrement a counter.
|
||||
*/
|
||||
void add(1:required binary key,
|
||||
2:required ColumnParent column_parent,
|
||||
3:required CounterColumn column,
|
||||
4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE)
|
||||
throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te),
|
||||
/**
|
||||
* Batch increment or decrement a counter.
|
||||
*/
|
||||
void batch_add(1:required map<binary, map<string, list<CounterMutation>>> update_map,
|
||||
2:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE)
|
||||
throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te),
|
||||
|
||||
/**
|
||||
* Return the counter at the specified column path.
|
||||
*/
|
||||
Counter get_counter(1:required binary key,
|
||||
2:required ColumnPath path,
|
||||
3:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE)
|
||||
throws (1:InvalidRequestException ire, 2:NotFoundException nfe, 3:UnavailableException ue, 4:TimedOutException te),
|
||||
|
||||
/**
|
||||
* Get a list of counters from the specified columns.
|
||||
*/
|
||||
list<Counter> get_counter_slice(1:required binary key,
|
||||
2:required ColumnParent column_parent,
|
||||
3:required SlicePredicate predicate,
|
||||
4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE)
|
||||
throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te),
|
||||
|
||||
/**
|
||||
* Get counter slices from multiple keys.
|
||||
*/
|
||||
map<binary,list<Counter>> multiget_counter_slice(1:required list<binary> keys,
|
||||
2:required ColumnParent column_parent,
|
||||
3:required SlicePredicate predicate,
|
||||
4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE)
|
||||
throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te),
|
||||
|
||||
/**
|
||||
* Remove a counter at the specified location.
|
||||
*/
|
||||
void remove_counter(1:required binary key,
|
||||
2:required ColumnPath path,
|
||||
3:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE)
|
||||
throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te),
|
||||
|
||||
|
||||
// Meta-APIs -- APIs to get information about the node or cluster,
|
||||
// rather than user data. The nodeprobe program provides usage examples.
|
||||
|
|
|
|||
|
|
@ -314,15 +314,15 @@ public class AuthenticationRequest implements TBase<AuthenticationRequest, Authe
|
|||
case 1: // CREDENTIALS
|
||||
if (field.type == TType.MAP) {
|
||||
{
|
||||
TMap _map20 = iprot.readMapBegin();
|
||||
this.credentials = new HashMap<String,String>(2*_map20.size);
|
||||
for (int _i21 = 0; _i21 < _map20.size; ++_i21)
|
||||
TMap _map24 = iprot.readMapBegin();
|
||||
this.credentials = new HashMap<String,String>(2*_map24.size);
|
||||
for (int _i25 = 0; _i25 < _map24.size; ++_i25)
|
||||
{
|
||||
String _key22;
|
||||
String _val23;
|
||||
_key22 = iprot.readString();
|
||||
_val23 = iprot.readString();
|
||||
this.credentials.put(_key22, _val23);
|
||||
String _key26;
|
||||
String _val27;
|
||||
_key26 = iprot.readString();
|
||||
_val27 = iprot.readString();
|
||||
this.credentials.put(_key26, _val27);
|
||||
}
|
||||
iprot.readMapEnd();
|
||||
}
|
||||
|
|
@ -349,10 +349,10 @@ public class AuthenticationRequest implements TBase<AuthenticationRequest, Authe
|
|||
oprot.writeFieldBegin(CREDENTIALS_FIELD_DESC);
|
||||
{
|
||||
oprot.writeMapBegin(new TMap(TType.STRING, TType.STRING, this.credentials.size()));
|
||||
for (Map.Entry<String, String> _iter24 : this.credentials.entrySet())
|
||||
for (Map.Entry<String, String> _iter28 : this.credentials.entrySet())
|
||||
{
|
||||
oprot.writeString(_iter24.getKey());
|
||||
oprot.writeString(_iter24.getValue());
|
||||
oprot.writeString(_iter28.getKey());
|
||||
oprot.writeString(_iter28.getValue());
|
||||
}
|
||||
oprot.writeMapEnd();
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -71,6 +71,7 @@ public class CfDef implements TBase<CfDef, CfDef._Fields>, java.io.Serializable,
|
|||
private static final TField MEMTABLE_FLUSH_AFTER_MINS_FIELD_DESC = new TField("memtable_flush_after_mins", TType.I32, (short)21);
|
||||
private static final TField MEMTABLE_THROUGHPUT_IN_MB_FIELD_DESC = new TField("memtable_throughput_in_mb", TType.I32, (short)22);
|
||||
private static final TField MEMTABLE_OPERATIONS_IN_MILLIONS_FIELD_DESC = new TField("memtable_operations_in_millions", TType.DOUBLE, (short)23);
|
||||
private static final TField REPLICATE_ON_WRITE_FIELD_DESC = new TField("replicate_on_write", TType.BOOL, (short)24);
|
||||
|
||||
public String keyspace;
|
||||
public String name;
|
||||
|
|
@ -92,6 +93,7 @@ public class CfDef implements TBase<CfDef, CfDef._Fields>, java.io.Serializable,
|
|||
public int memtable_flush_after_mins;
|
||||
public int memtable_throughput_in_mb;
|
||||
public double memtable_operations_in_millions;
|
||||
public boolean replicate_on_write;
|
||||
|
||||
/** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
|
||||
public enum _Fields implements TFieldIdEnum {
|
||||
|
|
@ -114,7 +116,8 @@ public class CfDef implements TBase<CfDef, CfDef._Fields>, java.io.Serializable,
|
|||
KEY_CACHE_SAVE_PERIOD_IN_SECONDS((short)20, "key_cache_save_period_in_seconds"),
|
||||
MEMTABLE_FLUSH_AFTER_MINS((short)21, "memtable_flush_after_mins"),
|
||||
MEMTABLE_THROUGHPUT_IN_MB((short)22, "memtable_throughput_in_mb"),
|
||||
MEMTABLE_OPERATIONS_IN_MILLIONS((short)23, "memtable_operations_in_millions");
|
||||
MEMTABLE_OPERATIONS_IN_MILLIONS((short)23, "memtable_operations_in_millions"),
|
||||
REPLICATE_ON_WRITE((short)24, "replicate_on_write");
|
||||
|
||||
private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();
|
||||
|
||||
|
|
@ -169,6 +172,8 @@ public class CfDef implements TBase<CfDef, CfDef._Fields>, java.io.Serializable,
|
|||
return MEMTABLE_THROUGHPUT_IN_MB;
|
||||
case 23: // MEMTABLE_OPERATIONS_IN_MILLIONS
|
||||
return MEMTABLE_OPERATIONS_IN_MILLIONS;
|
||||
case 24: // REPLICATE_ON_WRITE
|
||||
return REPLICATE_ON_WRITE;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
@ -221,7 +226,8 @@ public class CfDef implements TBase<CfDef, CfDef._Fields>, java.io.Serializable,
|
|||
private static final int __MEMTABLE_FLUSH_AFTER_MINS_ISSET_ID = 9;
|
||||
private static final int __MEMTABLE_THROUGHPUT_IN_MB_ISSET_ID = 10;
|
||||
private static final int __MEMTABLE_OPERATIONS_IN_MILLIONS_ISSET_ID = 11;
|
||||
private BitSet __isset_bit_vector = new BitSet(12);
|
||||
private static final int __REPLICATE_ON_WRITE_ISSET_ID = 12;
|
||||
private BitSet __isset_bit_vector = new BitSet(13);
|
||||
|
||||
public static final Map<_Fields, FieldMetaData> metaDataMap;
|
||||
static {
|
||||
|
|
@ -267,6 +273,8 @@ public class CfDef implements TBase<CfDef, CfDef._Fields>, java.io.Serializable,
|
|||
new FieldValueMetaData(TType.I32)));
|
||||
tmpMap.put(_Fields.MEMTABLE_OPERATIONS_IN_MILLIONS, new FieldMetaData("memtable_operations_in_millions", TFieldRequirementType.OPTIONAL,
|
||||
new FieldValueMetaData(TType.DOUBLE)));
|
||||
tmpMap.put(_Fields.REPLICATE_ON_WRITE, new FieldMetaData("replicate_on_write", TFieldRequirementType.OPTIONAL,
|
||||
new FieldValueMetaData(TType.BOOL)));
|
||||
metaDataMap = Collections.unmodifiableMap(tmpMap);
|
||||
FieldMetaData.addStructMetaDataMap(CfDef.class, metaDataMap);
|
||||
}
|
||||
|
|
@ -282,6 +290,8 @@ public class CfDef implements TBase<CfDef, CfDef._Fields>, java.io.Serializable,
|
|||
|
||||
this.read_repair_chance = 1;
|
||||
|
||||
this.replicate_on_write = false;
|
||||
|
||||
}
|
||||
|
||||
public CfDef(
|
||||
|
|
@ -339,6 +349,7 @@ public class CfDef implements TBase<CfDef, CfDef._Fields>, java.io.Serializable,
|
|||
this.memtable_flush_after_mins = other.memtable_flush_after_mins;
|
||||
this.memtable_throughput_in_mb = other.memtable_throughput_in_mb;
|
||||
this.memtable_operations_in_millions = other.memtable_operations_in_millions;
|
||||
this.replicate_on_write = other.replicate_on_write;
|
||||
}
|
||||
|
||||
public CfDef deepCopy() {
|
||||
|
|
@ -381,6 +392,8 @@ public class CfDef implements TBase<CfDef, CfDef._Fields>, java.io.Serializable,
|
|||
this.memtable_throughput_in_mb = 0;
|
||||
setMemtable_operations_in_millionsIsSet(false);
|
||||
this.memtable_operations_in_millions = 0.0;
|
||||
this.replicate_on_write = false;
|
||||
|
||||
}
|
||||
|
||||
public String getKeyspace() {
|
||||
|
|
@ -866,6 +879,29 @@ public class CfDef implements TBase<CfDef, CfDef._Fields>, java.io.Serializable,
|
|||
__isset_bit_vector.set(__MEMTABLE_OPERATIONS_IN_MILLIONS_ISSET_ID, value);
|
||||
}
|
||||
|
||||
public boolean isReplicate_on_write() {
|
||||
return this.replicate_on_write;
|
||||
}
|
||||
|
||||
public CfDef setReplicate_on_write(boolean replicate_on_write) {
|
||||
this.replicate_on_write = replicate_on_write;
|
||||
setReplicate_on_writeIsSet(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void unsetReplicate_on_write() {
|
||||
__isset_bit_vector.clear(__REPLICATE_ON_WRITE_ISSET_ID);
|
||||
}
|
||||
|
||||
/** Returns true if field replicate_on_write is set (has been asigned a value) and false otherwise */
|
||||
public boolean isSetReplicate_on_write() {
|
||||
return __isset_bit_vector.get(__REPLICATE_ON_WRITE_ISSET_ID);
|
||||
}
|
||||
|
||||
public void setReplicate_on_writeIsSet(boolean value) {
|
||||
__isset_bit_vector.set(__REPLICATE_ON_WRITE_ISSET_ID, value);
|
||||
}
|
||||
|
||||
public void setFieldValue(_Fields field, Object value) {
|
||||
switch (field) {
|
||||
case KEYSPACE:
|
||||
|
|
@ -1028,6 +1064,14 @@ public class CfDef implements TBase<CfDef, CfDef._Fields>, java.io.Serializable,
|
|||
}
|
||||
break;
|
||||
|
||||
case REPLICATE_ON_WRITE:
|
||||
if (value == null) {
|
||||
unsetReplicate_on_write();
|
||||
} else {
|
||||
setReplicate_on_write((Boolean)value);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1093,6 +1137,9 @@ public class CfDef implements TBase<CfDef, CfDef._Fields>, java.io.Serializable,
|
|||
case MEMTABLE_OPERATIONS_IN_MILLIONS:
|
||||
return new Double(getMemtable_operations_in_millions());
|
||||
|
||||
case REPLICATE_ON_WRITE:
|
||||
return new Boolean(isReplicate_on_write());
|
||||
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
|
@ -1144,6 +1191,8 @@ public class CfDef implements TBase<CfDef, CfDef._Fields>, java.io.Serializable,
|
|||
return isSetMemtable_throughput_in_mb();
|
||||
case MEMTABLE_OPERATIONS_IN_MILLIONS:
|
||||
return isSetMemtable_operations_in_millions();
|
||||
case REPLICATE_ON_WRITE:
|
||||
return isSetReplicate_on_write();
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
|
@ -1341,6 +1390,15 @@ public class CfDef implements TBase<CfDef, CfDef._Fields>, java.io.Serializable,
|
|||
return false;
|
||||
}
|
||||
|
||||
boolean this_present_replicate_on_write = true && this.isSetReplicate_on_write();
|
||||
boolean that_present_replicate_on_write = true && that.isSetReplicate_on_write();
|
||||
if (this_present_replicate_on_write || that_present_replicate_on_write) {
|
||||
if (!(this_present_replicate_on_write && that_present_replicate_on_write))
|
||||
return false;
|
||||
if (this.replicate_on_write != that.replicate_on_write)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1448,6 +1506,11 @@ public class CfDef implements TBase<CfDef, CfDef._Fields>, java.io.Serializable,
|
|||
if (present_memtable_operations_in_millions)
|
||||
builder.append(memtable_operations_in_millions);
|
||||
|
||||
boolean present_replicate_on_write = true && (isSetReplicate_on_write());
|
||||
builder.append(present_replicate_on_write);
|
||||
if (present_replicate_on_write)
|
||||
builder.append(replicate_on_write);
|
||||
|
||||
return builder.toHashCode();
|
||||
}
|
||||
|
||||
|
|
@ -1659,6 +1722,16 @@ public class CfDef implements TBase<CfDef, CfDef._Fields>, java.io.Serializable,
|
|||
return lastComparison;
|
||||
}
|
||||
}
|
||||
lastComparison = Boolean.valueOf(isSetReplicate_on_write()).compareTo(typedOther.isSetReplicate_on_write());
|
||||
if (lastComparison != 0) {
|
||||
return lastComparison;
|
||||
}
|
||||
if (isSetReplicate_on_write()) {
|
||||
lastComparison = TBaseHelper.compareTo(this.replicate_on_write, typedOther.replicate_on_write);
|
||||
if (lastComparison != 0) {
|
||||
return lastComparison;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1745,14 +1818,14 @@ public class CfDef implements TBase<CfDef, CfDef._Fields>, java.io.Serializable,
|
|||
case 13: // COLUMN_METADATA
|
||||
if (field.type == TType.LIST) {
|
||||
{
|
||||
TList _list25 = iprot.readListBegin();
|
||||
this.column_metadata = new ArrayList<ColumnDef>(_list25.size);
|
||||
for (int _i26 = 0; _i26 < _list25.size; ++_i26)
|
||||
TList _list29 = iprot.readListBegin();
|
||||
this.column_metadata = new ArrayList<ColumnDef>(_list29.size);
|
||||
for (int _i30 = 0; _i30 < _list29.size; ++_i30)
|
||||
{
|
||||
ColumnDef _elem27;
|
||||
_elem27 = new ColumnDef();
|
||||
_elem27.read(iprot);
|
||||
this.column_metadata.add(_elem27);
|
||||
ColumnDef _elem31;
|
||||
_elem31 = new ColumnDef();
|
||||
_elem31.read(iprot);
|
||||
this.column_metadata.add(_elem31);
|
||||
}
|
||||
iprot.readListEnd();
|
||||
}
|
||||
|
|
@ -1839,6 +1912,14 @@ public class CfDef implements TBase<CfDef, CfDef._Fields>, java.io.Serializable,
|
|||
TProtocolUtil.skip(iprot, field.type);
|
||||
}
|
||||
break;
|
||||
case 24: // REPLICATE_ON_WRITE
|
||||
if (field.type == TType.BOOL) {
|
||||
this.replicate_on_write = iprot.readBool();
|
||||
setReplicate_on_writeIsSet(true);
|
||||
} else {
|
||||
TProtocolUtil.skip(iprot, field.type);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
TProtocolUtil.skip(iprot, field.type);
|
||||
}
|
||||
|
|
@ -1912,9 +1993,9 @@ public class CfDef implements TBase<CfDef, CfDef._Fields>, java.io.Serializable,
|
|||
oprot.writeFieldBegin(COLUMN_METADATA_FIELD_DESC);
|
||||
{
|
||||
oprot.writeListBegin(new TList(TType.STRUCT, this.column_metadata.size()));
|
||||
for (ColumnDef _iter28 : this.column_metadata)
|
||||
for (ColumnDef _iter32 : this.column_metadata)
|
||||
{
|
||||
_iter28.write(oprot);
|
||||
_iter32.write(oprot);
|
||||
}
|
||||
oprot.writeListEnd();
|
||||
}
|
||||
|
|
@ -1973,6 +2054,11 @@ public class CfDef implements TBase<CfDef, CfDef._Fields>, java.io.Serializable,
|
|||
oprot.writeDouble(this.memtable_operations_in_millions);
|
||||
oprot.writeFieldEnd();
|
||||
}
|
||||
if (isSetReplicate_on_write()) {
|
||||
oprot.writeFieldBegin(REPLICATE_ON_WRITE_FIELD_DESC);
|
||||
oprot.writeBool(this.replicate_on_write);
|
||||
oprot.writeFieldEnd();
|
||||
}
|
||||
oprot.writeFieldStop();
|
||||
oprot.writeStructEnd();
|
||||
}
|
||||
|
|
@ -2129,6 +2215,12 @@ public class CfDef implements TBase<CfDef, CfDef._Fields>, java.io.Serializable,
|
|||
sb.append(this.memtable_operations_in_millions);
|
||||
first = false;
|
||||
}
|
||||
if (isSetReplicate_on_write()) {
|
||||
if (!first) sb.append(", ");
|
||||
sb.append("replicate_on_write:");
|
||||
sb.append(this.replicate_on_write);
|
||||
first = false;
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,433 @@
|
|||
/**
|
||||
* Autogenerated by Thrift
|
||||
*
|
||||
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
*/
|
||||
package org.apache.cassandra.thrift;
|
||||
/*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Collections;
|
||||
import java.util.BitSet;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.thrift.*;
|
||||
import org.apache.thrift.async.*;
|
||||
import org.apache.thrift.meta_data.*;
|
||||
import org.apache.thrift.transport.*;
|
||||
import org.apache.thrift.protocol.*;
|
||||
|
||||
public class Counter implements TBase<Counter, Counter._Fields>, java.io.Serializable, Cloneable {
|
||||
private static final TStruct STRUCT_DESC = new TStruct("Counter");
|
||||
|
||||
private static final TField COLUMN_FIELD_DESC = new TField("column", TType.STRUCT, (short)1);
|
||||
private static final TField SUPER_COLUMN_FIELD_DESC = new TField("super_column", TType.STRUCT, (short)2);
|
||||
|
||||
public CounterColumn column;
|
||||
public CounterSuperColumn super_column;
|
||||
|
||||
/** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
|
||||
public enum _Fields implements TFieldIdEnum {
|
||||
COLUMN((short)1, "column"),
|
||||
SUPER_COLUMN((short)2, "super_column");
|
||||
|
||||
private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();
|
||||
|
||||
static {
|
||||
for (_Fields field : EnumSet.allOf(_Fields.class)) {
|
||||
byName.put(field.getFieldName(), field);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the _Fields constant that matches fieldId, or null if its not found.
|
||||
*/
|
||||
public static _Fields findByThriftId(int fieldId) {
|
||||
switch(fieldId) {
|
||||
case 1: // COLUMN
|
||||
return COLUMN;
|
||||
case 2: // SUPER_COLUMN
|
||||
return SUPER_COLUMN;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the _Fields constant that matches fieldId, throwing an exception
|
||||
* if it is not found.
|
||||
*/
|
||||
public static _Fields findByThriftIdOrThrow(int fieldId) {
|
||||
_Fields fields = findByThriftId(fieldId);
|
||||
if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!");
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the _Fields constant that matches name, or null if its not found.
|
||||
*/
|
||||
public static _Fields findByName(String name) {
|
||||
return byName.get(name);
|
||||
}
|
||||
|
||||
private final short _thriftId;
|
||||
private final String _fieldName;
|
||||
|
||||
_Fields(short thriftId, String fieldName) {
|
||||
_thriftId = thriftId;
|
||||
_fieldName = fieldName;
|
||||
}
|
||||
|
||||
public short getThriftFieldId() {
|
||||
return _thriftId;
|
||||
}
|
||||
|
||||
public String getFieldName() {
|
||||
return _fieldName;
|
||||
}
|
||||
}
|
||||
|
||||
// isset id assignments
|
||||
|
||||
public static final Map<_Fields, FieldMetaData> metaDataMap;
|
||||
static {
|
||||
Map<_Fields, FieldMetaData> tmpMap = new EnumMap<_Fields, FieldMetaData>(_Fields.class);
|
||||
tmpMap.put(_Fields.COLUMN, new FieldMetaData("column", TFieldRequirementType.OPTIONAL,
|
||||
new StructMetaData(TType.STRUCT, CounterColumn.class)));
|
||||
tmpMap.put(_Fields.SUPER_COLUMN, new FieldMetaData("super_column", TFieldRequirementType.OPTIONAL,
|
||||
new StructMetaData(TType.STRUCT, CounterSuperColumn.class)));
|
||||
metaDataMap = Collections.unmodifiableMap(tmpMap);
|
||||
FieldMetaData.addStructMetaDataMap(Counter.class, metaDataMap);
|
||||
}
|
||||
|
||||
public Counter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a deep copy on <i>other</i>.
|
||||
*/
|
||||
public Counter(Counter other) {
|
||||
if (other.isSetColumn()) {
|
||||
this.column = new CounterColumn(other.column);
|
||||
}
|
||||
if (other.isSetSuper_column()) {
|
||||
this.super_column = new CounterSuperColumn(other.super_column);
|
||||
}
|
||||
}
|
||||
|
||||
public Counter deepCopy() {
|
||||
return new Counter(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.column = null;
|
||||
this.super_column = null;
|
||||
}
|
||||
|
||||
public CounterColumn getColumn() {
|
||||
return this.column;
|
||||
}
|
||||
|
||||
public Counter setColumn(CounterColumn column) {
|
||||
this.column = column;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void unsetColumn() {
|
||||
this.column = null;
|
||||
}
|
||||
|
||||
/** Returns true if field column is set (has been asigned a value) and false otherwise */
|
||||
public boolean isSetColumn() {
|
||||
return this.column != null;
|
||||
}
|
||||
|
||||
public void setColumnIsSet(boolean value) {
|
||||
if (!value) {
|
||||
this.column = null;
|
||||
}
|
||||
}
|
||||
|
||||
public CounterSuperColumn getSuper_column() {
|
||||
return this.super_column;
|
||||
}
|
||||
|
||||
public Counter setSuper_column(CounterSuperColumn super_column) {
|
||||
this.super_column = super_column;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void unsetSuper_column() {
|
||||
this.super_column = null;
|
||||
}
|
||||
|
||||
/** Returns true if field super_column is set (has been asigned a value) and false otherwise */
|
||||
public boolean isSetSuper_column() {
|
||||
return this.super_column != null;
|
||||
}
|
||||
|
||||
public void setSuper_columnIsSet(boolean value) {
|
||||
if (!value) {
|
||||
this.super_column = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setFieldValue(_Fields field, Object value) {
|
||||
switch (field) {
|
||||
case COLUMN:
|
||||
if (value == null) {
|
||||
unsetColumn();
|
||||
} else {
|
||||
setColumn((CounterColumn)value);
|
||||
}
|
||||
break;
|
||||
|
||||
case SUPER_COLUMN:
|
||||
if (value == null) {
|
||||
unsetSuper_column();
|
||||
} else {
|
||||
setSuper_column((CounterSuperColumn)value);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public Object getFieldValue(_Fields field) {
|
||||
switch (field) {
|
||||
case COLUMN:
|
||||
return getColumn();
|
||||
|
||||
case SUPER_COLUMN:
|
||||
return getSuper_column();
|
||||
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/** Returns true if field corresponding to fieldID is set (has been asigned a value) and false otherwise */
|
||||
public boolean isSet(_Fields field) {
|
||||
if (field == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
switch (field) {
|
||||
case COLUMN:
|
||||
return isSetColumn();
|
||||
case SUPER_COLUMN:
|
||||
return isSetSuper_column();
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
if (that == null)
|
||||
return false;
|
||||
if (that instanceof Counter)
|
||||
return this.equals((Counter)that);
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean equals(Counter that) {
|
||||
if (that == null)
|
||||
return false;
|
||||
|
||||
boolean this_present_column = true && this.isSetColumn();
|
||||
boolean that_present_column = true && that.isSetColumn();
|
||||
if (this_present_column || that_present_column) {
|
||||
if (!(this_present_column && that_present_column))
|
||||
return false;
|
||||
if (!this.column.equals(that.column))
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean this_present_super_column = true && this.isSetSuper_column();
|
||||
boolean that_present_super_column = true && that.isSetSuper_column();
|
||||
if (this_present_super_column || that_present_super_column) {
|
||||
if (!(this_present_super_column && that_present_super_column))
|
||||
return false;
|
||||
if (!this.super_column.equals(that.super_column))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
HashCodeBuilder builder = new HashCodeBuilder();
|
||||
|
||||
boolean present_column = true && (isSetColumn());
|
||||
builder.append(present_column);
|
||||
if (present_column)
|
||||
builder.append(column);
|
||||
|
||||
boolean present_super_column = true && (isSetSuper_column());
|
||||
builder.append(present_super_column);
|
||||
if (present_super_column)
|
||||
builder.append(super_column);
|
||||
|
||||
return builder.toHashCode();
|
||||
}
|
||||
|
||||
public int compareTo(Counter other) {
|
||||
if (!getClass().equals(other.getClass())) {
|
||||
return getClass().getName().compareTo(other.getClass().getName());
|
||||
}
|
||||
|
||||
int lastComparison = 0;
|
||||
Counter typedOther = (Counter)other;
|
||||
|
||||
lastComparison = Boolean.valueOf(isSetColumn()).compareTo(typedOther.isSetColumn());
|
||||
if (lastComparison != 0) {
|
||||
return lastComparison;
|
||||
}
|
||||
if (isSetColumn()) {
|
||||
lastComparison = TBaseHelper.compareTo(this.column, typedOther.column);
|
||||
if (lastComparison != 0) {
|
||||
return lastComparison;
|
||||
}
|
||||
}
|
||||
lastComparison = Boolean.valueOf(isSetSuper_column()).compareTo(typedOther.isSetSuper_column());
|
||||
if (lastComparison != 0) {
|
||||
return lastComparison;
|
||||
}
|
||||
if (isSetSuper_column()) {
|
||||
lastComparison = TBaseHelper.compareTo(this.super_column, typedOther.super_column);
|
||||
if (lastComparison != 0) {
|
||||
return lastComparison;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public _Fields fieldForId(int fieldId) {
|
||||
return _Fields.findByThriftId(fieldId);
|
||||
}
|
||||
|
||||
public void read(TProtocol iprot) throws TException {
|
||||
TField field;
|
||||
iprot.readStructBegin();
|
||||
while (true)
|
||||
{
|
||||
field = iprot.readFieldBegin();
|
||||
if (field.type == TType.STOP) {
|
||||
break;
|
||||
}
|
||||
switch (field.id) {
|
||||
case 1: // COLUMN
|
||||
if (field.type == TType.STRUCT) {
|
||||
this.column = new CounterColumn();
|
||||
this.column.read(iprot);
|
||||
} else {
|
||||
TProtocolUtil.skip(iprot, field.type);
|
||||
}
|
||||
break;
|
||||
case 2: // SUPER_COLUMN
|
||||
if (field.type == TType.STRUCT) {
|
||||
this.super_column = new CounterSuperColumn();
|
||||
this.super_column.read(iprot);
|
||||
} else {
|
||||
TProtocolUtil.skip(iprot, field.type);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
TProtocolUtil.skip(iprot, field.type);
|
||||
}
|
||||
iprot.readFieldEnd();
|
||||
}
|
||||
iprot.readStructEnd();
|
||||
|
||||
// check for required fields of primitive type, which can't be checked in the validate method
|
||||
validate();
|
||||
}
|
||||
|
||||
public void write(TProtocol oprot) throws TException {
|
||||
validate();
|
||||
|
||||
oprot.writeStructBegin(STRUCT_DESC);
|
||||
if (this.column != null) {
|
||||
if (isSetColumn()) {
|
||||
oprot.writeFieldBegin(COLUMN_FIELD_DESC);
|
||||
this.column.write(oprot);
|
||||
oprot.writeFieldEnd();
|
||||
}
|
||||
}
|
||||
if (this.super_column != null) {
|
||||
if (isSetSuper_column()) {
|
||||
oprot.writeFieldBegin(SUPER_COLUMN_FIELD_DESC);
|
||||
this.super_column.write(oprot);
|
||||
oprot.writeFieldEnd();
|
||||
}
|
||||
}
|
||||
oprot.writeFieldStop();
|
||||
oprot.writeStructEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("Counter(");
|
||||
boolean first = true;
|
||||
|
||||
if (isSetColumn()) {
|
||||
sb.append("column:");
|
||||
if (this.column == null) {
|
||||
sb.append("null");
|
||||
} else {
|
||||
sb.append(this.column);
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
if (isSetSuper_column()) {
|
||||
if (!first) sb.append(", ");
|
||||
sb.append("super_column:");
|
||||
if (this.super_column == null) {
|
||||
sb.append("null");
|
||||
} else {
|
||||
sb.append(this.super_column);
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void validate() throws TException {
|
||||
// check for required fields
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,448 @@
|
|||
/**
|
||||
* Autogenerated by Thrift
|
||||
*
|
||||
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
*/
|
||||
package org.apache.cassandra.thrift;
|
||||
/*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Collections;
|
||||
import java.util.BitSet;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.thrift.*;
|
||||
import org.apache.thrift.async.*;
|
||||
import org.apache.thrift.meta_data.*;
|
||||
import org.apache.thrift.transport.*;
|
||||
import org.apache.thrift.protocol.*;
|
||||
|
||||
public class CounterColumn implements TBase<CounterColumn, CounterColumn._Fields>, java.io.Serializable, Cloneable {
|
||||
private static final TStruct STRUCT_DESC = new TStruct("CounterColumn");
|
||||
|
||||
private static final TField NAME_FIELD_DESC = new TField("name", TType.STRING, (short)1);
|
||||
private static final TField VALUE_FIELD_DESC = new TField("value", TType.I64, (short)2);
|
||||
|
||||
public ByteBuffer name;
|
||||
public long value;
|
||||
|
||||
/** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
|
||||
public enum _Fields implements TFieldIdEnum {
|
||||
NAME((short)1, "name"),
|
||||
VALUE((short)2, "value");
|
||||
|
||||
private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();
|
||||
|
||||
static {
|
||||
for (_Fields field : EnumSet.allOf(_Fields.class)) {
|
||||
byName.put(field.getFieldName(), field);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the _Fields constant that matches fieldId, or null if its not found.
|
||||
*/
|
||||
public static _Fields findByThriftId(int fieldId) {
|
||||
switch(fieldId) {
|
||||
case 1: // NAME
|
||||
return NAME;
|
||||
case 2: // VALUE
|
||||
return VALUE;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the _Fields constant that matches fieldId, throwing an exception
|
||||
* if it is not found.
|
||||
*/
|
||||
public static _Fields findByThriftIdOrThrow(int fieldId) {
|
||||
_Fields fields = findByThriftId(fieldId);
|
||||
if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!");
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the _Fields constant that matches name, or null if its not found.
|
||||
*/
|
||||
public static _Fields findByName(String name) {
|
||||
return byName.get(name);
|
||||
}
|
||||
|
||||
private final short _thriftId;
|
||||
private final String _fieldName;
|
||||
|
||||
_Fields(short thriftId, String fieldName) {
|
||||
_thriftId = thriftId;
|
||||
_fieldName = fieldName;
|
||||
}
|
||||
|
||||
public short getThriftFieldId() {
|
||||
return _thriftId;
|
||||
}
|
||||
|
||||
public String getFieldName() {
|
||||
return _fieldName;
|
||||
}
|
||||
}
|
||||
|
||||
// isset id assignments
|
||||
private static final int __VALUE_ISSET_ID = 0;
|
||||
private BitSet __isset_bit_vector = new BitSet(1);
|
||||
|
||||
public static final Map<_Fields, FieldMetaData> metaDataMap;
|
||||
static {
|
||||
Map<_Fields, FieldMetaData> tmpMap = new EnumMap<_Fields, FieldMetaData>(_Fields.class);
|
||||
tmpMap.put(_Fields.NAME, new FieldMetaData("name", TFieldRequirementType.REQUIRED,
|
||||
new FieldValueMetaData(TType.STRING)));
|
||||
tmpMap.put(_Fields.VALUE, new FieldMetaData("value", TFieldRequirementType.REQUIRED,
|
||||
new FieldValueMetaData(TType.I64)));
|
||||
metaDataMap = Collections.unmodifiableMap(tmpMap);
|
||||
FieldMetaData.addStructMetaDataMap(CounterColumn.class, metaDataMap);
|
||||
}
|
||||
|
||||
public CounterColumn() {
|
||||
}
|
||||
|
||||
public CounterColumn(
|
||||
ByteBuffer name,
|
||||
long value)
|
||||
{
|
||||
this();
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
setValueIsSet(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a deep copy on <i>other</i>.
|
||||
*/
|
||||
public CounterColumn(CounterColumn other) {
|
||||
__isset_bit_vector.clear();
|
||||
__isset_bit_vector.or(other.__isset_bit_vector);
|
||||
if (other.isSetName()) {
|
||||
this.name = TBaseHelper.copyBinary(other.name);
|
||||
;
|
||||
}
|
||||
this.value = other.value;
|
||||
}
|
||||
|
||||
public CounterColumn deepCopy() {
|
||||
return new CounterColumn(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.name = null;
|
||||
setValueIsSet(false);
|
||||
this.value = 0;
|
||||
}
|
||||
|
||||
public byte[] getName() {
|
||||
setName(TBaseHelper.rightSize(name));
|
||||
return name.array();
|
||||
}
|
||||
|
||||
public ByteBuffer BufferForName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public CounterColumn setName(byte[] name) {
|
||||
setName(ByteBuffer.wrap(name));
|
||||
return this;
|
||||
}
|
||||
|
||||
public CounterColumn setName(ByteBuffer name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void unsetName() {
|
||||
this.name = null;
|
||||
}
|
||||
|
||||
/** Returns true if field name is set (has been asigned a value) and false otherwise */
|
||||
public boolean isSetName() {
|
||||
return this.name != null;
|
||||
}
|
||||
|
||||
public void setNameIsSet(boolean value) {
|
||||
if (!value) {
|
||||
this.name = null;
|
||||
}
|
||||
}
|
||||
|
||||
public long getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public CounterColumn setValue(long value) {
|
||||
this.value = value;
|
||||
setValueIsSet(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void unsetValue() {
|
||||
__isset_bit_vector.clear(__VALUE_ISSET_ID);
|
||||
}
|
||||
|
||||
/** Returns true if field value is set (has been asigned a value) and false otherwise */
|
||||
public boolean isSetValue() {
|
||||
return __isset_bit_vector.get(__VALUE_ISSET_ID);
|
||||
}
|
||||
|
||||
public void setValueIsSet(boolean value) {
|
||||
__isset_bit_vector.set(__VALUE_ISSET_ID, value);
|
||||
}
|
||||
|
||||
public void setFieldValue(_Fields field, Object value) {
|
||||
switch (field) {
|
||||
case NAME:
|
||||
if (value == null) {
|
||||
unsetName();
|
||||
} else {
|
||||
setName((ByteBuffer)value);
|
||||
}
|
||||
break;
|
||||
|
||||
case VALUE:
|
||||
if (value == null) {
|
||||
unsetValue();
|
||||
} else {
|
||||
setValue((Long)value);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public Object getFieldValue(_Fields field) {
|
||||
switch (field) {
|
||||
case NAME:
|
||||
return getName();
|
||||
|
||||
case VALUE:
|
||||
return new Long(getValue());
|
||||
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/** Returns true if field corresponding to fieldID is set (has been asigned a value) and false otherwise */
|
||||
public boolean isSet(_Fields field) {
|
||||
if (field == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
switch (field) {
|
||||
case NAME:
|
||||
return isSetName();
|
||||
case VALUE:
|
||||
return isSetValue();
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
if (that == null)
|
||||
return false;
|
||||
if (that instanceof CounterColumn)
|
||||
return this.equals((CounterColumn)that);
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean equals(CounterColumn that) {
|
||||
if (that == null)
|
||||
return false;
|
||||
|
||||
boolean this_present_name = true && this.isSetName();
|
||||
boolean that_present_name = true && that.isSetName();
|
||||
if (this_present_name || that_present_name) {
|
||||
if (!(this_present_name && that_present_name))
|
||||
return false;
|
||||
if (!this.name.equals(that.name))
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean this_present_value = true;
|
||||
boolean that_present_value = true;
|
||||
if (this_present_value || that_present_value) {
|
||||
if (!(this_present_value && that_present_value))
|
||||
return false;
|
||||
if (this.value != that.value)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
HashCodeBuilder builder = new HashCodeBuilder();
|
||||
|
||||
boolean present_name = true && (isSetName());
|
||||
builder.append(present_name);
|
||||
if (present_name)
|
||||
builder.append(name);
|
||||
|
||||
boolean present_value = true;
|
||||
builder.append(present_value);
|
||||
if (present_value)
|
||||
builder.append(value);
|
||||
|
||||
return builder.toHashCode();
|
||||
}
|
||||
|
||||
public int compareTo(CounterColumn other) {
|
||||
if (!getClass().equals(other.getClass())) {
|
||||
return getClass().getName().compareTo(other.getClass().getName());
|
||||
}
|
||||
|
||||
int lastComparison = 0;
|
||||
CounterColumn typedOther = (CounterColumn)other;
|
||||
|
||||
lastComparison = Boolean.valueOf(isSetName()).compareTo(typedOther.isSetName());
|
||||
if (lastComparison != 0) {
|
||||
return lastComparison;
|
||||
}
|
||||
if (isSetName()) {
|
||||
lastComparison = TBaseHelper.compareTo(this.name, typedOther.name);
|
||||
if (lastComparison != 0) {
|
||||
return lastComparison;
|
||||
}
|
||||
}
|
||||
lastComparison = Boolean.valueOf(isSetValue()).compareTo(typedOther.isSetValue());
|
||||
if (lastComparison != 0) {
|
||||
return lastComparison;
|
||||
}
|
||||
if (isSetValue()) {
|
||||
lastComparison = TBaseHelper.compareTo(this.value, typedOther.value);
|
||||
if (lastComparison != 0) {
|
||||
return lastComparison;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public _Fields fieldForId(int fieldId) {
|
||||
return _Fields.findByThriftId(fieldId);
|
||||
}
|
||||
|
||||
public void read(TProtocol iprot) throws TException {
|
||||
TField field;
|
||||
iprot.readStructBegin();
|
||||
while (true)
|
||||
{
|
||||
field = iprot.readFieldBegin();
|
||||
if (field.type == TType.STOP) {
|
||||
break;
|
||||
}
|
||||
switch (field.id) {
|
||||
case 1: // NAME
|
||||
if (field.type == TType.STRING) {
|
||||
this.name = iprot.readBinary();
|
||||
} else {
|
||||
TProtocolUtil.skip(iprot, field.type);
|
||||
}
|
||||
break;
|
||||
case 2: // VALUE
|
||||
if (field.type == TType.I64) {
|
||||
this.value = iprot.readI64();
|
||||
setValueIsSet(true);
|
||||
} else {
|
||||
TProtocolUtil.skip(iprot, field.type);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
TProtocolUtil.skip(iprot, field.type);
|
||||
}
|
||||
iprot.readFieldEnd();
|
||||
}
|
||||
iprot.readStructEnd();
|
||||
|
||||
// check for required fields of primitive type, which can't be checked in the validate method
|
||||
if (!isSetValue()) {
|
||||
throw new TProtocolException("Required field 'value' was not found in serialized data! Struct: " + toString());
|
||||
}
|
||||
validate();
|
||||
}
|
||||
|
||||
public void write(TProtocol oprot) throws TException {
|
||||
validate();
|
||||
|
||||
oprot.writeStructBegin(STRUCT_DESC);
|
||||
if (this.name != null) {
|
||||
oprot.writeFieldBegin(NAME_FIELD_DESC);
|
||||
oprot.writeBinary(this.name);
|
||||
oprot.writeFieldEnd();
|
||||
}
|
||||
oprot.writeFieldBegin(VALUE_FIELD_DESC);
|
||||
oprot.writeI64(this.value);
|
||||
oprot.writeFieldEnd();
|
||||
oprot.writeFieldStop();
|
||||
oprot.writeStructEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("CounterColumn(");
|
||||
boolean first = true;
|
||||
|
||||
sb.append("name:");
|
||||
if (this.name == null) {
|
||||
sb.append("null");
|
||||
} else {
|
||||
TBaseHelper.toString(this.name, sb);
|
||||
}
|
||||
first = false;
|
||||
if (!first) sb.append(", ");
|
||||
sb.append("value:");
|
||||
sb.append(this.value);
|
||||
first = false;
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void validate() throws TException {
|
||||
// check for required fields
|
||||
if (name == null) {
|
||||
throw new TProtocolException("Required field 'name' was not present! Struct: " + toString());
|
||||
}
|
||||
// alas, we cannot check 'value' because it's a primitive and you chose the non-beans generator.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,443 @@
|
|||
/**
|
||||
* Autogenerated by Thrift
|
||||
*
|
||||
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
*/
|
||||
package org.apache.cassandra.thrift;
|
||||
/*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Collections;
|
||||
import java.util.BitSet;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.thrift.*;
|
||||
import org.apache.thrift.async.*;
|
||||
import org.apache.thrift.meta_data.*;
|
||||
import org.apache.thrift.transport.*;
|
||||
import org.apache.thrift.protocol.*;
|
||||
|
||||
public class CounterDeletion implements TBase<CounterDeletion, CounterDeletion._Fields>, java.io.Serializable, Cloneable {
|
||||
private static final TStruct STRUCT_DESC = new TStruct("CounterDeletion");
|
||||
|
||||
private static final TField SUPER_COLUMN_FIELD_DESC = new TField("super_column", TType.STRING, (short)1);
|
||||
private static final TField PREDICATE_FIELD_DESC = new TField("predicate", TType.STRUCT, (short)2);
|
||||
|
||||
public ByteBuffer super_column;
|
||||
public SlicePredicate predicate;
|
||||
|
||||
/** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
|
||||
public enum _Fields implements TFieldIdEnum {
|
||||
SUPER_COLUMN((short)1, "super_column"),
|
||||
PREDICATE((short)2, "predicate");
|
||||
|
||||
private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();
|
||||
|
||||
static {
|
||||
for (_Fields field : EnumSet.allOf(_Fields.class)) {
|
||||
byName.put(field.getFieldName(), field);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the _Fields constant that matches fieldId, or null if its not found.
|
||||
*/
|
||||
public static _Fields findByThriftId(int fieldId) {
|
||||
switch(fieldId) {
|
||||
case 1: // SUPER_COLUMN
|
||||
return SUPER_COLUMN;
|
||||
case 2: // PREDICATE
|
||||
return PREDICATE;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the _Fields constant that matches fieldId, throwing an exception
|
||||
* if it is not found.
|
||||
*/
|
||||
public static _Fields findByThriftIdOrThrow(int fieldId) {
|
||||
_Fields fields = findByThriftId(fieldId);
|
||||
if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!");
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the _Fields constant that matches name, or null if its not found.
|
||||
*/
|
||||
public static _Fields findByName(String name) {
|
||||
return byName.get(name);
|
||||
}
|
||||
|
||||
private final short _thriftId;
|
||||
private final String _fieldName;
|
||||
|
||||
_Fields(short thriftId, String fieldName) {
|
||||
_thriftId = thriftId;
|
||||
_fieldName = fieldName;
|
||||
}
|
||||
|
||||
public short getThriftFieldId() {
|
||||
return _thriftId;
|
||||
}
|
||||
|
||||
public String getFieldName() {
|
||||
return _fieldName;
|
||||
}
|
||||
}
|
||||
|
||||
// isset id assignments
|
||||
|
||||
public static final Map<_Fields, FieldMetaData> metaDataMap;
|
||||
static {
|
||||
Map<_Fields, FieldMetaData> tmpMap = new EnumMap<_Fields, FieldMetaData>(_Fields.class);
|
||||
tmpMap.put(_Fields.SUPER_COLUMN, new FieldMetaData("super_column", TFieldRequirementType.OPTIONAL,
|
||||
new FieldValueMetaData(TType.STRING)));
|
||||
tmpMap.put(_Fields.PREDICATE, new FieldMetaData("predicate", TFieldRequirementType.OPTIONAL,
|
||||
new StructMetaData(TType.STRUCT, SlicePredicate.class)));
|
||||
metaDataMap = Collections.unmodifiableMap(tmpMap);
|
||||
FieldMetaData.addStructMetaDataMap(CounterDeletion.class, metaDataMap);
|
||||
}
|
||||
|
||||
public CounterDeletion() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a deep copy on <i>other</i>.
|
||||
*/
|
||||
public CounterDeletion(CounterDeletion other) {
|
||||
if (other.isSetSuper_column()) {
|
||||
this.super_column = TBaseHelper.copyBinary(other.super_column);
|
||||
;
|
||||
}
|
||||
if (other.isSetPredicate()) {
|
||||
this.predicate = new SlicePredicate(other.predicate);
|
||||
}
|
||||
}
|
||||
|
||||
public CounterDeletion deepCopy() {
|
||||
return new CounterDeletion(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.super_column = null;
|
||||
this.predicate = null;
|
||||
}
|
||||
|
||||
public byte[] getSuper_column() {
|
||||
setSuper_column(TBaseHelper.rightSize(super_column));
|
||||
return super_column.array();
|
||||
}
|
||||
|
||||
public ByteBuffer BufferForSuper_column() {
|
||||
return super_column;
|
||||
}
|
||||
|
||||
public CounterDeletion setSuper_column(byte[] super_column) {
|
||||
setSuper_column(ByteBuffer.wrap(super_column));
|
||||
return this;
|
||||
}
|
||||
|
||||
public CounterDeletion setSuper_column(ByteBuffer super_column) {
|
||||
this.super_column = super_column;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void unsetSuper_column() {
|
||||
this.super_column = null;
|
||||
}
|
||||
|
||||
/** Returns true if field super_column is set (has been asigned a value) and false otherwise */
|
||||
public boolean isSetSuper_column() {
|
||||
return this.super_column != null;
|
||||
}
|
||||
|
||||
public void setSuper_columnIsSet(boolean value) {
|
||||
if (!value) {
|
||||
this.super_column = null;
|
||||
}
|
||||
}
|
||||
|
||||
public SlicePredicate getPredicate() {
|
||||
return this.predicate;
|
||||
}
|
||||
|
||||
public CounterDeletion setPredicate(SlicePredicate predicate) {
|
||||
this.predicate = predicate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void unsetPredicate() {
|
||||
this.predicate = null;
|
||||
}
|
||||
|
||||
/** Returns true if field predicate is set (has been asigned a value) and false otherwise */
|
||||
public boolean isSetPredicate() {
|
||||
return this.predicate != null;
|
||||
}
|
||||
|
||||
public void setPredicateIsSet(boolean value) {
|
||||
if (!value) {
|
||||
this.predicate = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setFieldValue(_Fields field, Object value) {
|
||||
switch (field) {
|
||||
case SUPER_COLUMN:
|
||||
if (value == null) {
|
||||
unsetSuper_column();
|
||||
} else {
|
||||
setSuper_column((ByteBuffer)value);
|
||||
}
|
||||
break;
|
||||
|
||||
case PREDICATE:
|
||||
if (value == null) {
|
||||
unsetPredicate();
|
||||
} else {
|
||||
setPredicate((SlicePredicate)value);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public Object getFieldValue(_Fields field) {
|
||||
switch (field) {
|
||||
case SUPER_COLUMN:
|
||||
return getSuper_column();
|
||||
|
||||
case PREDICATE:
|
||||
return getPredicate();
|
||||
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/** Returns true if field corresponding to fieldID is set (has been asigned a value) and false otherwise */
|
||||
public boolean isSet(_Fields field) {
|
||||
if (field == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
switch (field) {
|
||||
case SUPER_COLUMN:
|
||||
return isSetSuper_column();
|
||||
case PREDICATE:
|
||||
return isSetPredicate();
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
if (that == null)
|
||||
return false;
|
||||
if (that instanceof CounterDeletion)
|
||||
return this.equals((CounterDeletion)that);
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean equals(CounterDeletion that) {
|
||||
if (that == null)
|
||||
return false;
|
||||
|
||||
boolean this_present_super_column = true && this.isSetSuper_column();
|
||||
boolean that_present_super_column = true && that.isSetSuper_column();
|
||||
if (this_present_super_column || that_present_super_column) {
|
||||
if (!(this_present_super_column && that_present_super_column))
|
||||
return false;
|
||||
if (!this.super_column.equals(that.super_column))
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean this_present_predicate = true && this.isSetPredicate();
|
||||
boolean that_present_predicate = true && that.isSetPredicate();
|
||||
if (this_present_predicate || that_present_predicate) {
|
||||
if (!(this_present_predicate && that_present_predicate))
|
||||
return false;
|
||||
if (!this.predicate.equals(that.predicate))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
HashCodeBuilder builder = new HashCodeBuilder();
|
||||
|
||||
boolean present_super_column = true && (isSetSuper_column());
|
||||
builder.append(present_super_column);
|
||||
if (present_super_column)
|
||||
builder.append(super_column);
|
||||
|
||||
boolean present_predicate = true && (isSetPredicate());
|
||||
builder.append(present_predicate);
|
||||
if (present_predicate)
|
||||
builder.append(predicate);
|
||||
|
||||
return builder.toHashCode();
|
||||
}
|
||||
|
||||
public int compareTo(CounterDeletion other) {
|
||||
if (!getClass().equals(other.getClass())) {
|
||||
return getClass().getName().compareTo(other.getClass().getName());
|
||||
}
|
||||
|
||||
int lastComparison = 0;
|
||||
CounterDeletion typedOther = (CounterDeletion)other;
|
||||
|
||||
lastComparison = Boolean.valueOf(isSetSuper_column()).compareTo(typedOther.isSetSuper_column());
|
||||
if (lastComparison != 0) {
|
||||
return lastComparison;
|
||||
}
|
||||
if (isSetSuper_column()) {
|
||||
lastComparison = TBaseHelper.compareTo(this.super_column, typedOther.super_column);
|
||||
if (lastComparison != 0) {
|
||||
return lastComparison;
|
||||
}
|
||||
}
|
||||
lastComparison = Boolean.valueOf(isSetPredicate()).compareTo(typedOther.isSetPredicate());
|
||||
if (lastComparison != 0) {
|
||||
return lastComparison;
|
||||
}
|
||||
if (isSetPredicate()) {
|
||||
lastComparison = TBaseHelper.compareTo(this.predicate, typedOther.predicate);
|
||||
if (lastComparison != 0) {
|
||||
return lastComparison;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public _Fields fieldForId(int fieldId) {
|
||||
return _Fields.findByThriftId(fieldId);
|
||||
}
|
||||
|
||||
public void read(TProtocol iprot) throws TException {
|
||||
TField field;
|
||||
iprot.readStructBegin();
|
||||
while (true)
|
||||
{
|
||||
field = iprot.readFieldBegin();
|
||||
if (field.type == TType.STOP) {
|
||||
break;
|
||||
}
|
||||
switch (field.id) {
|
||||
case 1: // SUPER_COLUMN
|
||||
if (field.type == TType.STRING) {
|
||||
this.super_column = iprot.readBinary();
|
||||
} else {
|
||||
TProtocolUtil.skip(iprot, field.type);
|
||||
}
|
||||
break;
|
||||
case 2: // PREDICATE
|
||||
if (field.type == TType.STRUCT) {
|
||||
this.predicate = new SlicePredicate();
|
||||
this.predicate.read(iprot);
|
||||
} else {
|
||||
TProtocolUtil.skip(iprot, field.type);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
TProtocolUtil.skip(iprot, field.type);
|
||||
}
|
||||
iprot.readFieldEnd();
|
||||
}
|
||||
iprot.readStructEnd();
|
||||
|
||||
// check for required fields of primitive type, which can't be checked in the validate method
|
||||
validate();
|
||||
}
|
||||
|
||||
public void write(TProtocol oprot) throws TException {
|
||||
validate();
|
||||
|
||||
oprot.writeStructBegin(STRUCT_DESC);
|
||||
if (this.super_column != null) {
|
||||
if (isSetSuper_column()) {
|
||||
oprot.writeFieldBegin(SUPER_COLUMN_FIELD_DESC);
|
||||
oprot.writeBinary(this.super_column);
|
||||
oprot.writeFieldEnd();
|
||||
}
|
||||
}
|
||||
if (this.predicate != null) {
|
||||
if (isSetPredicate()) {
|
||||
oprot.writeFieldBegin(PREDICATE_FIELD_DESC);
|
||||
this.predicate.write(oprot);
|
||||
oprot.writeFieldEnd();
|
||||
}
|
||||
}
|
||||
oprot.writeFieldStop();
|
||||
oprot.writeStructEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("CounterDeletion(");
|
||||
boolean first = true;
|
||||
|
||||
if (isSetSuper_column()) {
|
||||
sb.append("super_column:");
|
||||
if (this.super_column == null) {
|
||||
sb.append("null");
|
||||
} else {
|
||||
TBaseHelper.toString(this.super_column, sb);
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
if (isSetPredicate()) {
|
||||
if (!first) sb.append(", ");
|
||||
sb.append("predicate:");
|
||||
if (this.predicate == null) {
|
||||
sb.append("null");
|
||||
} else {
|
||||
sb.append(this.predicate);
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void validate() throws TException {
|
||||
// check for required fields
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,438 @@
|
|||
/**
|
||||
* Autogenerated by Thrift
|
||||
*
|
||||
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
*/
|
||||
package org.apache.cassandra.thrift;
|
||||
/*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Collections;
|
||||
import java.util.BitSet;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.thrift.*;
|
||||
import org.apache.thrift.async.*;
|
||||
import org.apache.thrift.meta_data.*;
|
||||
import org.apache.thrift.transport.*;
|
||||
import org.apache.thrift.protocol.*;
|
||||
|
||||
/**
|
||||
* A CounterMutation is either an insert, represented by filling counter, or a deletion, represented by filling the deletion attribute.
|
||||
* @param counter. An insert to a counter column or supercolumn
|
||||
* @param deletion. A deletion of a counter column or supercolumn
|
||||
*/
|
||||
public class CounterMutation implements TBase<CounterMutation, CounterMutation._Fields>, java.io.Serializable, Cloneable {
|
||||
private static final TStruct STRUCT_DESC = new TStruct("CounterMutation");
|
||||
|
||||
private static final TField COUNTER_FIELD_DESC = new TField("counter", TType.STRUCT, (short)1);
|
||||
private static final TField DELETION_FIELD_DESC = new TField("deletion", TType.STRUCT, (short)2);
|
||||
|
||||
public Counter counter;
|
||||
public CounterDeletion deletion;
|
||||
|
||||
/** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
|
||||
public enum _Fields implements TFieldIdEnum {
|
||||
COUNTER((short)1, "counter"),
|
||||
DELETION((short)2, "deletion");
|
||||
|
||||
private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();
|
||||
|
||||
static {
|
||||
for (_Fields field : EnumSet.allOf(_Fields.class)) {
|
||||
byName.put(field.getFieldName(), field);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the _Fields constant that matches fieldId, or null if its not found.
|
||||
*/
|
||||
public static _Fields findByThriftId(int fieldId) {
|
||||
switch(fieldId) {
|
||||
case 1: // COUNTER
|
||||
return COUNTER;
|
||||
case 2: // DELETION
|
||||
return DELETION;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the _Fields constant that matches fieldId, throwing an exception
|
||||
* if it is not found.
|
||||
*/
|
||||
public static _Fields findByThriftIdOrThrow(int fieldId) {
|
||||
_Fields fields = findByThriftId(fieldId);
|
||||
if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!");
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the _Fields constant that matches name, or null if its not found.
|
||||
*/
|
||||
public static _Fields findByName(String name) {
|
||||
return byName.get(name);
|
||||
}
|
||||
|
||||
private final short _thriftId;
|
||||
private final String _fieldName;
|
||||
|
||||
_Fields(short thriftId, String fieldName) {
|
||||
_thriftId = thriftId;
|
||||
_fieldName = fieldName;
|
||||
}
|
||||
|
||||
public short getThriftFieldId() {
|
||||
return _thriftId;
|
||||
}
|
||||
|
||||
public String getFieldName() {
|
||||
return _fieldName;
|
||||
}
|
||||
}
|
||||
|
||||
// isset id assignments
|
||||
|
||||
public static final Map<_Fields, FieldMetaData> metaDataMap;
|
||||
static {
|
||||
Map<_Fields, FieldMetaData> tmpMap = new EnumMap<_Fields, FieldMetaData>(_Fields.class);
|
||||
tmpMap.put(_Fields.COUNTER, new FieldMetaData("counter", TFieldRequirementType.OPTIONAL,
|
||||
new StructMetaData(TType.STRUCT, Counter.class)));
|
||||
tmpMap.put(_Fields.DELETION, new FieldMetaData("deletion", TFieldRequirementType.OPTIONAL,
|
||||
new StructMetaData(TType.STRUCT, CounterDeletion.class)));
|
||||
metaDataMap = Collections.unmodifiableMap(tmpMap);
|
||||
FieldMetaData.addStructMetaDataMap(CounterMutation.class, metaDataMap);
|
||||
}
|
||||
|
||||
public CounterMutation() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a deep copy on <i>other</i>.
|
||||
*/
|
||||
public CounterMutation(CounterMutation other) {
|
||||
if (other.isSetCounter()) {
|
||||
this.counter = new Counter(other.counter);
|
||||
}
|
||||
if (other.isSetDeletion()) {
|
||||
this.deletion = new CounterDeletion(other.deletion);
|
||||
}
|
||||
}
|
||||
|
||||
public CounterMutation deepCopy() {
|
||||
return new CounterMutation(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.counter = null;
|
||||
this.deletion = null;
|
||||
}
|
||||
|
||||
public Counter getCounter() {
|
||||
return this.counter;
|
||||
}
|
||||
|
||||
public CounterMutation setCounter(Counter counter) {
|
||||
this.counter = counter;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void unsetCounter() {
|
||||
this.counter = null;
|
||||
}
|
||||
|
||||
/** Returns true if field counter is set (has been asigned a value) and false otherwise */
|
||||
public boolean isSetCounter() {
|
||||
return this.counter != null;
|
||||
}
|
||||
|
||||
public void setCounterIsSet(boolean value) {
|
||||
if (!value) {
|
||||
this.counter = null;
|
||||
}
|
||||
}
|
||||
|
||||
public CounterDeletion getDeletion() {
|
||||
return this.deletion;
|
||||
}
|
||||
|
||||
public CounterMutation setDeletion(CounterDeletion deletion) {
|
||||
this.deletion = deletion;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void unsetDeletion() {
|
||||
this.deletion = null;
|
||||
}
|
||||
|
||||
/** Returns true if field deletion is set (has been asigned a value) and false otherwise */
|
||||
public boolean isSetDeletion() {
|
||||
return this.deletion != null;
|
||||
}
|
||||
|
||||
public void setDeletionIsSet(boolean value) {
|
||||
if (!value) {
|
||||
this.deletion = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setFieldValue(_Fields field, Object value) {
|
||||
switch (field) {
|
||||
case COUNTER:
|
||||
if (value == null) {
|
||||
unsetCounter();
|
||||
} else {
|
||||
setCounter((Counter)value);
|
||||
}
|
||||
break;
|
||||
|
||||
case DELETION:
|
||||
if (value == null) {
|
||||
unsetDeletion();
|
||||
} else {
|
||||
setDeletion((CounterDeletion)value);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public Object getFieldValue(_Fields field) {
|
||||
switch (field) {
|
||||
case COUNTER:
|
||||
return getCounter();
|
||||
|
||||
case DELETION:
|
||||
return getDeletion();
|
||||
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/** Returns true if field corresponding to fieldID is set (has been asigned a value) and false otherwise */
|
||||
public boolean isSet(_Fields field) {
|
||||
if (field == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
switch (field) {
|
||||
case COUNTER:
|
||||
return isSetCounter();
|
||||
case DELETION:
|
||||
return isSetDeletion();
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
if (that == null)
|
||||
return false;
|
||||
if (that instanceof CounterMutation)
|
||||
return this.equals((CounterMutation)that);
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean equals(CounterMutation that) {
|
||||
if (that == null)
|
||||
return false;
|
||||
|
||||
boolean this_present_counter = true && this.isSetCounter();
|
||||
boolean that_present_counter = true && that.isSetCounter();
|
||||
if (this_present_counter || that_present_counter) {
|
||||
if (!(this_present_counter && that_present_counter))
|
||||
return false;
|
||||
if (!this.counter.equals(that.counter))
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean this_present_deletion = true && this.isSetDeletion();
|
||||
boolean that_present_deletion = true && that.isSetDeletion();
|
||||
if (this_present_deletion || that_present_deletion) {
|
||||
if (!(this_present_deletion && that_present_deletion))
|
||||
return false;
|
||||
if (!this.deletion.equals(that.deletion))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
HashCodeBuilder builder = new HashCodeBuilder();
|
||||
|
||||
boolean present_counter = true && (isSetCounter());
|
||||
builder.append(present_counter);
|
||||
if (present_counter)
|
||||
builder.append(counter);
|
||||
|
||||
boolean present_deletion = true && (isSetDeletion());
|
||||
builder.append(present_deletion);
|
||||
if (present_deletion)
|
||||
builder.append(deletion);
|
||||
|
||||
return builder.toHashCode();
|
||||
}
|
||||
|
||||
public int compareTo(CounterMutation other) {
|
||||
if (!getClass().equals(other.getClass())) {
|
||||
return getClass().getName().compareTo(other.getClass().getName());
|
||||
}
|
||||
|
||||
int lastComparison = 0;
|
||||
CounterMutation typedOther = (CounterMutation)other;
|
||||
|
||||
lastComparison = Boolean.valueOf(isSetCounter()).compareTo(typedOther.isSetCounter());
|
||||
if (lastComparison != 0) {
|
||||
return lastComparison;
|
||||
}
|
||||
if (isSetCounter()) {
|
||||
lastComparison = TBaseHelper.compareTo(this.counter, typedOther.counter);
|
||||
if (lastComparison != 0) {
|
||||
return lastComparison;
|
||||
}
|
||||
}
|
||||
lastComparison = Boolean.valueOf(isSetDeletion()).compareTo(typedOther.isSetDeletion());
|
||||
if (lastComparison != 0) {
|
||||
return lastComparison;
|
||||
}
|
||||
if (isSetDeletion()) {
|
||||
lastComparison = TBaseHelper.compareTo(this.deletion, typedOther.deletion);
|
||||
if (lastComparison != 0) {
|
||||
return lastComparison;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public _Fields fieldForId(int fieldId) {
|
||||
return _Fields.findByThriftId(fieldId);
|
||||
}
|
||||
|
||||
public void read(TProtocol iprot) throws TException {
|
||||
TField field;
|
||||
iprot.readStructBegin();
|
||||
while (true)
|
||||
{
|
||||
field = iprot.readFieldBegin();
|
||||
if (field.type == TType.STOP) {
|
||||
break;
|
||||
}
|
||||
switch (field.id) {
|
||||
case 1: // COUNTER
|
||||
if (field.type == TType.STRUCT) {
|
||||
this.counter = new Counter();
|
||||
this.counter.read(iprot);
|
||||
} else {
|
||||
TProtocolUtil.skip(iprot, field.type);
|
||||
}
|
||||
break;
|
||||
case 2: // DELETION
|
||||
if (field.type == TType.STRUCT) {
|
||||
this.deletion = new CounterDeletion();
|
||||
this.deletion.read(iprot);
|
||||
} else {
|
||||
TProtocolUtil.skip(iprot, field.type);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
TProtocolUtil.skip(iprot, field.type);
|
||||
}
|
||||
iprot.readFieldEnd();
|
||||
}
|
||||
iprot.readStructEnd();
|
||||
|
||||
// check for required fields of primitive type, which can't be checked in the validate method
|
||||
validate();
|
||||
}
|
||||
|
||||
public void write(TProtocol oprot) throws TException {
|
||||
validate();
|
||||
|
||||
oprot.writeStructBegin(STRUCT_DESC);
|
||||
if (this.counter != null) {
|
||||
if (isSetCounter()) {
|
||||
oprot.writeFieldBegin(COUNTER_FIELD_DESC);
|
||||
this.counter.write(oprot);
|
||||
oprot.writeFieldEnd();
|
||||
}
|
||||
}
|
||||
if (this.deletion != null) {
|
||||
if (isSetDeletion()) {
|
||||
oprot.writeFieldBegin(DELETION_FIELD_DESC);
|
||||
this.deletion.write(oprot);
|
||||
oprot.writeFieldEnd();
|
||||
}
|
||||
}
|
||||
oprot.writeFieldStop();
|
||||
oprot.writeStructEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("CounterMutation(");
|
||||
boolean first = true;
|
||||
|
||||
if (isSetCounter()) {
|
||||
sb.append("counter:");
|
||||
if (this.counter == null) {
|
||||
sb.append("null");
|
||||
} else {
|
||||
sb.append(this.counter);
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
if (isSetDeletion()) {
|
||||
if (!first) sb.append(", ");
|
||||
sb.append("deletion:");
|
||||
if (this.deletion == null) {
|
||||
sb.append("null");
|
||||
} else {
|
||||
sb.append(this.deletion);
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void validate() throws TException {
|
||||
// check for required fields
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,487 @@
|
|||
/**
|
||||
* Autogenerated by Thrift
|
||||
*
|
||||
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
*/
|
||||
package org.apache.cassandra.thrift;
|
||||
/*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Collections;
|
||||
import java.util.BitSet;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.thrift.*;
|
||||
import org.apache.thrift.async.*;
|
||||
import org.apache.thrift.meta_data.*;
|
||||
import org.apache.thrift.transport.*;
|
||||
import org.apache.thrift.protocol.*;
|
||||
|
||||
public class CounterSuperColumn implements TBase<CounterSuperColumn, CounterSuperColumn._Fields>, java.io.Serializable, Cloneable {
|
||||
private static final TStruct STRUCT_DESC = new TStruct("CounterSuperColumn");
|
||||
|
||||
private static final TField NAME_FIELD_DESC = new TField("name", TType.STRING, (short)1);
|
||||
private static final TField COLUMNS_FIELD_DESC = new TField("columns", TType.LIST, (short)2);
|
||||
|
||||
public ByteBuffer name;
|
||||
public List<CounterColumn> columns;
|
||||
|
||||
/** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
|
||||
public enum _Fields implements TFieldIdEnum {
|
||||
NAME((short)1, "name"),
|
||||
COLUMNS((short)2, "columns");
|
||||
|
||||
private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();
|
||||
|
||||
static {
|
||||
for (_Fields field : EnumSet.allOf(_Fields.class)) {
|
||||
byName.put(field.getFieldName(), field);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the _Fields constant that matches fieldId, or null if its not found.
|
||||
*/
|
||||
public static _Fields findByThriftId(int fieldId) {
|
||||
switch(fieldId) {
|
||||
case 1: // NAME
|
||||
return NAME;
|
||||
case 2: // COLUMNS
|
||||
return COLUMNS;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the _Fields constant that matches fieldId, throwing an exception
|
||||
* if it is not found.
|
||||
*/
|
||||
public static _Fields findByThriftIdOrThrow(int fieldId) {
|
||||
_Fields fields = findByThriftId(fieldId);
|
||||
if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!");
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the _Fields constant that matches name, or null if its not found.
|
||||
*/
|
||||
public static _Fields findByName(String name) {
|
||||
return byName.get(name);
|
||||
}
|
||||
|
||||
private final short _thriftId;
|
||||
private final String _fieldName;
|
||||
|
||||
_Fields(short thriftId, String fieldName) {
|
||||
_thriftId = thriftId;
|
||||
_fieldName = fieldName;
|
||||
}
|
||||
|
||||
public short getThriftFieldId() {
|
||||
return _thriftId;
|
||||
}
|
||||
|
||||
public String getFieldName() {
|
||||
return _fieldName;
|
||||
}
|
||||
}
|
||||
|
||||
// isset id assignments
|
||||
|
||||
public static final Map<_Fields, FieldMetaData> metaDataMap;
|
||||
static {
|
||||
Map<_Fields, FieldMetaData> tmpMap = new EnumMap<_Fields, FieldMetaData>(_Fields.class);
|
||||
tmpMap.put(_Fields.NAME, new FieldMetaData("name", TFieldRequirementType.REQUIRED,
|
||||
new FieldValueMetaData(TType.STRING)));
|
||||
tmpMap.put(_Fields.COLUMNS, new FieldMetaData("columns", TFieldRequirementType.REQUIRED,
|
||||
new ListMetaData(TType.LIST,
|
||||
new StructMetaData(TType.STRUCT, CounterColumn.class))));
|
||||
metaDataMap = Collections.unmodifiableMap(tmpMap);
|
||||
FieldMetaData.addStructMetaDataMap(CounterSuperColumn.class, metaDataMap);
|
||||
}
|
||||
|
||||
public CounterSuperColumn() {
|
||||
}
|
||||
|
||||
public CounterSuperColumn(
|
||||
ByteBuffer name,
|
||||
List<CounterColumn> columns)
|
||||
{
|
||||
this();
|
||||
this.name = name;
|
||||
this.columns = columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a deep copy on <i>other</i>.
|
||||
*/
|
||||
public CounterSuperColumn(CounterSuperColumn other) {
|
||||
if (other.isSetName()) {
|
||||
this.name = TBaseHelper.copyBinary(other.name);
|
||||
;
|
||||
}
|
||||
if (other.isSetColumns()) {
|
||||
List<CounterColumn> __this__columns = new ArrayList<CounterColumn>();
|
||||
for (CounterColumn other_element : other.columns) {
|
||||
__this__columns.add(new CounterColumn(other_element));
|
||||
}
|
||||
this.columns = __this__columns;
|
||||
}
|
||||
}
|
||||
|
||||
public CounterSuperColumn deepCopy() {
|
||||
return new CounterSuperColumn(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.name = null;
|
||||
this.columns = null;
|
||||
}
|
||||
|
||||
public byte[] getName() {
|
||||
setName(TBaseHelper.rightSize(name));
|
||||
return name.array();
|
||||
}
|
||||
|
||||
public ByteBuffer BufferForName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public CounterSuperColumn setName(byte[] name) {
|
||||
setName(ByteBuffer.wrap(name));
|
||||
return this;
|
||||
}
|
||||
|
||||
public CounterSuperColumn setName(ByteBuffer name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void unsetName() {
|
||||
this.name = null;
|
||||
}
|
||||
|
||||
/** Returns true if field name is set (has been asigned a value) and false otherwise */
|
||||
public boolean isSetName() {
|
||||
return this.name != null;
|
||||
}
|
||||
|
||||
public void setNameIsSet(boolean value) {
|
||||
if (!value) {
|
||||
this.name = null;
|
||||
}
|
||||
}
|
||||
|
||||
public int getColumnsSize() {
|
||||
return (this.columns == null) ? 0 : this.columns.size();
|
||||
}
|
||||
|
||||
public java.util.Iterator<CounterColumn> getColumnsIterator() {
|
||||
return (this.columns == null) ? null : this.columns.iterator();
|
||||
}
|
||||
|
||||
public void addToColumns(CounterColumn elem) {
|
||||
if (this.columns == null) {
|
||||
this.columns = new ArrayList<CounterColumn>();
|
||||
}
|
||||
this.columns.add(elem);
|
||||
}
|
||||
|
||||
public List<CounterColumn> getColumns() {
|
||||
return this.columns;
|
||||
}
|
||||
|
||||
public CounterSuperColumn setColumns(List<CounterColumn> columns) {
|
||||
this.columns = columns;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void unsetColumns() {
|
||||
this.columns = null;
|
||||
}
|
||||
|
||||
/** Returns true if field columns is set (has been asigned a value) and false otherwise */
|
||||
public boolean isSetColumns() {
|
||||
return this.columns != null;
|
||||
}
|
||||
|
||||
public void setColumnsIsSet(boolean value) {
|
||||
if (!value) {
|
||||
this.columns = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setFieldValue(_Fields field, Object value) {
|
||||
switch (field) {
|
||||
case NAME:
|
||||
if (value == null) {
|
||||
unsetName();
|
||||
} else {
|
||||
setName((ByteBuffer)value);
|
||||
}
|
||||
break;
|
||||
|
||||
case COLUMNS:
|
||||
if (value == null) {
|
||||
unsetColumns();
|
||||
} else {
|
||||
setColumns((List<CounterColumn>)value);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public Object getFieldValue(_Fields field) {
|
||||
switch (field) {
|
||||
case NAME:
|
||||
return getName();
|
||||
|
||||
case COLUMNS:
|
||||
return getColumns();
|
||||
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/** Returns true if field corresponding to fieldID is set (has been asigned a value) and false otherwise */
|
||||
public boolean isSet(_Fields field) {
|
||||
if (field == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
switch (field) {
|
||||
case NAME:
|
||||
return isSetName();
|
||||
case COLUMNS:
|
||||
return isSetColumns();
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
if (that == null)
|
||||
return false;
|
||||
if (that instanceof CounterSuperColumn)
|
||||
return this.equals((CounterSuperColumn)that);
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean equals(CounterSuperColumn that) {
|
||||
if (that == null)
|
||||
return false;
|
||||
|
||||
boolean this_present_name = true && this.isSetName();
|
||||
boolean that_present_name = true && that.isSetName();
|
||||
if (this_present_name || that_present_name) {
|
||||
if (!(this_present_name && that_present_name))
|
||||
return false;
|
||||
if (!this.name.equals(that.name))
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean this_present_columns = true && this.isSetColumns();
|
||||
boolean that_present_columns = true && that.isSetColumns();
|
||||
if (this_present_columns || that_present_columns) {
|
||||
if (!(this_present_columns && that_present_columns))
|
||||
return false;
|
||||
if (!this.columns.equals(that.columns))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
HashCodeBuilder builder = new HashCodeBuilder();
|
||||
|
||||
boolean present_name = true && (isSetName());
|
||||
builder.append(present_name);
|
||||
if (present_name)
|
||||
builder.append(name);
|
||||
|
||||
boolean present_columns = true && (isSetColumns());
|
||||
builder.append(present_columns);
|
||||
if (present_columns)
|
||||
builder.append(columns);
|
||||
|
||||
return builder.toHashCode();
|
||||
}
|
||||
|
||||
public int compareTo(CounterSuperColumn other) {
|
||||
if (!getClass().equals(other.getClass())) {
|
||||
return getClass().getName().compareTo(other.getClass().getName());
|
||||
}
|
||||
|
||||
int lastComparison = 0;
|
||||
CounterSuperColumn typedOther = (CounterSuperColumn)other;
|
||||
|
||||
lastComparison = Boolean.valueOf(isSetName()).compareTo(typedOther.isSetName());
|
||||
if (lastComparison != 0) {
|
||||
return lastComparison;
|
||||
}
|
||||
if (isSetName()) {
|
||||
lastComparison = TBaseHelper.compareTo(this.name, typedOther.name);
|
||||
if (lastComparison != 0) {
|
||||
return lastComparison;
|
||||
}
|
||||
}
|
||||
lastComparison = Boolean.valueOf(isSetColumns()).compareTo(typedOther.isSetColumns());
|
||||
if (lastComparison != 0) {
|
||||
return lastComparison;
|
||||
}
|
||||
if (isSetColumns()) {
|
||||
lastComparison = TBaseHelper.compareTo(this.columns, typedOther.columns);
|
||||
if (lastComparison != 0) {
|
||||
return lastComparison;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public _Fields fieldForId(int fieldId) {
|
||||
return _Fields.findByThriftId(fieldId);
|
||||
}
|
||||
|
||||
public void read(TProtocol iprot) throws TException {
|
||||
TField field;
|
||||
iprot.readStructBegin();
|
||||
while (true)
|
||||
{
|
||||
field = iprot.readFieldBegin();
|
||||
if (field.type == TType.STOP) {
|
||||
break;
|
||||
}
|
||||
switch (field.id) {
|
||||
case 1: // NAME
|
||||
if (field.type == TType.STRING) {
|
||||
this.name = iprot.readBinary();
|
||||
} else {
|
||||
TProtocolUtil.skip(iprot, field.type);
|
||||
}
|
||||
break;
|
||||
case 2: // COLUMNS
|
||||
if (field.type == TType.LIST) {
|
||||
{
|
||||
TList _list4 = iprot.readListBegin();
|
||||
this.columns = new ArrayList<CounterColumn>(_list4.size);
|
||||
for (int _i5 = 0; _i5 < _list4.size; ++_i5)
|
||||
{
|
||||
CounterColumn _elem6;
|
||||
_elem6 = new CounterColumn();
|
||||
_elem6.read(iprot);
|
||||
this.columns.add(_elem6);
|
||||
}
|
||||
iprot.readListEnd();
|
||||
}
|
||||
} else {
|
||||
TProtocolUtil.skip(iprot, field.type);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
TProtocolUtil.skip(iprot, field.type);
|
||||
}
|
||||
iprot.readFieldEnd();
|
||||
}
|
||||
iprot.readStructEnd();
|
||||
|
||||
// check for required fields of primitive type, which can't be checked in the validate method
|
||||
validate();
|
||||
}
|
||||
|
||||
public void write(TProtocol oprot) throws TException {
|
||||
validate();
|
||||
|
||||
oprot.writeStructBegin(STRUCT_DESC);
|
||||
if (this.name != null) {
|
||||
oprot.writeFieldBegin(NAME_FIELD_DESC);
|
||||
oprot.writeBinary(this.name);
|
||||
oprot.writeFieldEnd();
|
||||
}
|
||||
if (this.columns != null) {
|
||||
oprot.writeFieldBegin(COLUMNS_FIELD_DESC);
|
||||
{
|
||||
oprot.writeListBegin(new TList(TType.STRUCT, this.columns.size()));
|
||||
for (CounterColumn _iter7 : this.columns)
|
||||
{
|
||||
_iter7.write(oprot);
|
||||
}
|
||||
oprot.writeListEnd();
|
||||
}
|
||||
oprot.writeFieldEnd();
|
||||
}
|
||||
oprot.writeFieldStop();
|
||||
oprot.writeStructEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("CounterSuperColumn(");
|
||||
boolean first = true;
|
||||
|
||||
sb.append("name:");
|
||||
if (this.name == null) {
|
||||
sb.append("null");
|
||||
} else {
|
||||
TBaseHelper.toString(this.name, sb);
|
||||
}
|
||||
first = false;
|
||||
if (!first) sb.append(", ");
|
||||
sb.append("columns:");
|
||||
if (this.columns == null) {
|
||||
sb.append("null");
|
||||
} else {
|
||||
sb.append(this.columns);
|
||||
}
|
||||
first = false;
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void validate() throws TException {
|
||||
// check for required fields
|
||||
if (name == null) {
|
||||
throw new TProtocolException("Required field 'name' was not present! Struct: " + toString());
|
||||
}
|
||||
if (columns == null) {
|
||||
throw new TProtocolException("Required field 'columns' was not present! Struct: " + toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -470,14 +470,14 @@ public class IndexClause implements TBase<IndexClause, IndexClause._Fields>, jav
|
|||
case 1: // EXPRESSIONS
|
||||
if (field.type == TType.LIST) {
|
||||
{
|
||||
TList _list8 = iprot.readListBegin();
|
||||
this.expressions = new ArrayList<IndexExpression>(_list8.size);
|
||||
for (int _i9 = 0; _i9 < _list8.size; ++_i9)
|
||||
TList _list12 = iprot.readListBegin();
|
||||
this.expressions = new ArrayList<IndexExpression>(_list12.size);
|
||||
for (int _i13 = 0; _i13 < _list12.size; ++_i13)
|
||||
{
|
||||
IndexExpression _elem10;
|
||||
_elem10 = new IndexExpression();
|
||||
_elem10.read(iprot);
|
||||
this.expressions.add(_elem10);
|
||||
IndexExpression _elem14;
|
||||
_elem14 = new IndexExpression();
|
||||
_elem14.read(iprot);
|
||||
this.expressions.add(_elem14);
|
||||
}
|
||||
iprot.readListEnd();
|
||||
}
|
||||
|
|
@ -522,9 +522,9 @@ public class IndexClause implements TBase<IndexClause, IndexClause._Fields>, jav
|
|||
oprot.writeFieldBegin(EXPRESSIONS_FIELD_DESC);
|
||||
{
|
||||
oprot.writeListBegin(new TList(TType.STRUCT, this.expressions.size()));
|
||||
for (IndexExpression _iter11 : this.expressions)
|
||||
for (IndexExpression _iter15 : this.expressions)
|
||||
{
|
||||
_iter11.write(oprot);
|
||||
_iter15.write(oprot);
|
||||
}
|
||||
oprot.writeListEnd();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -405,14 +405,14 @@ public class KeySlice implements TBase<KeySlice, KeySlice._Fields>, java.io.Seri
|
|||
case 2: // COLUMNS
|
||||
if (field.type == TType.LIST) {
|
||||
{
|
||||
TList _list12 = iprot.readListBegin();
|
||||
this.columns = new ArrayList<ColumnOrSuperColumn>(_list12.size);
|
||||
for (int _i13 = 0; _i13 < _list12.size; ++_i13)
|
||||
TList _list16 = iprot.readListBegin();
|
||||
this.columns = new ArrayList<ColumnOrSuperColumn>(_list16.size);
|
||||
for (int _i17 = 0; _i17 < _list16.size; ++_i17)
|
||||
{
|
||||
ColumnOrSuperColumn _elem14;
|
||||
_elem14 = new ColumnOrSuperColumn();
|
||||
_elem14.read(iprot);
|
||||
this.columns.add(_elem14);
|
||||
ColumnOrSuperColumn _elem18;
|
||||
_elem18 = new ColumnOrSuperColumn();
|
||||
_elem18.read(iprot);
|
||||
this.columns.add(_elem18);
|
||||
}
|
||||
iprot.readListEnd();
|
||||
}
|
||||
|
|
@ -444,9 +444,9 @@ public class KeySlice implements TBase<KeySlice, KeySlice._Fields>, java.io.Seri
|
|||
oprot.writeFieldBegin(COLUMNS_FIELD_DESC);
|
||||
{
|
||||
oprot.writeListBegin(new TList(TType.STRUCT, this.columns.size()));
|
||||
for (ColumnOrSuperColumn _iter15 : this.columns)
|
||||
for (ColumnOrSuperColumn _iter19 : this.columns)
|
||||
{
|
||||
_iter15.write(oprot);
|
||||
_iter19.write(oprot);
|
||||
}
|
||||
oprot.writeListEnd();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -642,15 +642,15 @@ public class KsDef implements TBase<KsDef, KsDef._Fields>, java.io.Serializable,
|
|||
case 3: // STRATEGY_OPTIONS
|
||||
if (field.type == TType.MAP) {
|
||||
{
|
||||
TMap _map29 = iprot.readMapBegin();
|
||||
this.strategy_options = new HashMap<String,String>(2*_map29.size);
|
||||
for (int _i30 = 0; _i30 < _map29.size; ++_i30)
|
||||
TMap _map33 = iprot.readMapBegin();
|
||||
this.strategy_options = new HashMap<String,String>(2*_map33.size);
|
||||
for (int _i34 = 0; _i34 < _map33.size; ++_i34)
|
||||
{
|
||||
String _key31;
|
||||
String _val32;
|
||||
_key31 = iprot.readString();
|
||||
_val32 = iprot.readString();
|
||||
this.strategy_options.put(_key31, _val32);
|
||||
String _key35;
|
||||
String _val36;
|
||||
_key35 = iprot.readString();
|
||||
_val36 = iprot.readString();
|
||||
this.strategy_options.put(_key35, _val36);
|
||||
}
|
||||
iprot.readMapEnd();
|
||||
}
|
||||
|
|
@ -669,14 +669,14 @@ public class KsDef implements TBase<KsDef, KsDef._Fields>, java.io.Serializable,
|
|||
case 5: // CF_DEFS
|
||||
if (field.type == TType.LIST) {
|
||||
{
|
||||
TList _list33 = iprot.readListBegin();
|
||||
this.cf_defs = new ArrayList<CfDef>(_list33.size);
|
||||
for (int _i34 = 0; _i34 < _list33.size; ++_i34)
|
||||
TList _list37 = iprot.readListBegin();
|
||||
this.cf_defs = new ArrayList<CfDef>(_list37.size);
|
||||
for (int _i38 = 0; _i38 < _list37.size; ++_i38)
|
||||
{
|
||||
CfDef _elem35;
|
||||
_elem35 = new CfDef();
|
||||
_elem35.read(iprot);
|
||||
this.cf_defs.add(_elem35);
|
||||
CfDef _elem39;
|
||||
_elem39 = new CfDef();
|
||||
_elem39.read(iprot);
|
||||
this.cf_defs.add(_elem39);
|
||||
}
|
||||
iprot.readListEnd();
|
||||
}
|
||||
|
|
@ -717,10 +717,10 @@ public class KsDef implements TBase<KsDef, KsDef._Fields>, java.io.Serializable,
|
|||
oprot.writeFieldBegin(STRATEGY_OPTIONS_FIELD_DESC);
|
||||
{
|
||||
oprot.writeMapBegin(new TMap(TType.STRING, TType.STRING, this.strategy_options.size()));
|
||||
for (Map.Entry<String, String> _iter36 : this.strategy_options.entrySet())
|
||||
for (Map.Entry<String, String> _iter40 : this.strategy_options.entrySet())
|
||||
{
|
||||
oprot.writeString(_iter36.getKey());
|
||||
oprot.writeString(_iter36.getValue());
|
||||
oprot.writeString(_iter40.getKey());
|
||||
oprot.writeString(_iter40.getValue());
|
||||
}
|
||||
oprot.writeMapEnd();
|
||||
}
|
||||
|
|
@ -734,9 +734,9 @@ public class KsDef implements TBase<KsDef, KsDef._Fields>, java.io.Serializable,
|
|||
oprot.writeFieldBegin(CF_DEFS_FIELD_DESC);
|
||||
{
|
||||
oprot.writeListBegin(new TList(TType.STRUCT, this.cf_defs.size()));
|
||||
for (CfDef _iter37 : this.cf_defs)
|
||||
for (CfDef _iter41 : this.cf_defs)
|
||||
{
|
||||
_iter37.write(oprot);
|
||||
_iter41.write(oprot);
|
||||
}
|
||||
oprot.writeListEnd();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -385,13 +385,13 @@ public class SlicePredicate implements TBase<SlicePredicate, SlicePredicate._Fie
|
|||
case 1: // COLUMN_NAMES
|
||||
if (field.type == TType.LIST) {
|
||||
{
|
||||
TList _list4 = iprot.readListBegin();
|
||||
this.column_names = new ArrayList<ByteBuffer>(_list4.size);
|
||||
for (int _i5 = 0; _i5 < _list4.size; ++_i5)
|
||||
TList _list8 = iprot.readListBegin();
|
||||
this.column_names = new ArrayList<ByteBuffer>(_list8.size);
|
||||
for (int _i9 = 0; _i9 < _list8.size; ++_i9)
|
||||
{
|
||||
ByteBuffer _elem6;
|
||||
_elem6 = iprot.readBinary();
|
||||
this.column_names.add(_elem6);
|
||||
ByteBuffer _elem10;
|
||||
_elem10 = iprot.readBinary();
|
||||
this.column_names.add(_elem10);
|
||||
}
|
||||
iprot.readListEnd();
|
||||
}
|
||||
|
|
@ -427,9 +427,9 @@ public class SlicePredicate implements TBase<SlicePredicate, SlicePredicate._Fie
|
|||
oprot.writeFieldBegin(COLUMN_NAMES_FIELD_DESC);
|
||||
{
|
||||
oprot.writeListBegin(new TList(TType.STRING, this.column_names.size()));
|
||||
for (ByteBuffer _iter7 : this.column_names)
|
||||
for (ByteBuffer _iter11 : this.column_names)
|
||||
{
|
||||
oprot.writeBinary(_iter7);
|
||||
oprot.writeBinary(_iter11);
|
||||
}
|
||||
oprot.writeListEnd();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -468,13 +468,13 @@ public class TokenRange implements TBase<TokenRange, TokenRange._Fields>, java.i
|
|||
case 3: // ENDPOINTS
|
||||
if (field.type == TType.LIST) {
|
||||
{
|
||||
TList _list16 = iprot.readListBegin();
|
||||
this.endpoints = new ArrayList<String>(_list16.size);
|
||||
for (int _i17 = 0; _i17 < _list16.size; ++_i17)
|
||||
TList _list20 = iprot.readListBegin();
|
||||
this.endpoints = new ArrayList<String>(_list20.size);
|
||||
for (int _i21 = 0; _i21 < _list20.size; ++_i21)
|
||||
{
|
||||
String _elem18;
|
||||
_elem18 = iprot.readString();
|
||||
this.endpoints.add(_elem18);
|
||||
String _elem22;
|
||||
_elem22 = iprot.readString();
|
||||
this.endpoints.add(_elem22);
|
||||
}
|
||||
iprot.readListEnd();
|
||||
}
|
||||
|
|
@ -511,9 +511,9 @@ public class TokenRange implements TBase<TokenRange, TokenRange._Fields>, java.i
|
|||
oprot.writeFieldBegin(ENDPOINTS_FIELD_DESC);
|
||||
{
|
||||
oprot.writeListBegin(new TList(TType.STRING, this.endpoints.size()));
|
||||
for (String _iter19 : this.endpoints)
|
||||
for (String _iter23 : this.endpoints)
|
||||
{
|
||||
oprot.writeString(_iter19);
|
||||
oprot.writeString(_iter23);
|
||||
}
|
||||
oprot.writeListEnd();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,6 @@ public class CassandraServer implements Cassandra {
|
|||
|
||||
// CfDef default values
|
||||
private final static String D_CF_CFTYPE = "Standard";
|
||||
private final static String D_CF_CFCLOCKTYPE = "Timestamp";
|
||||
private final static String D_CF_COMPTYPE = "BytesType";
|
||||
private final static String D_CF_SUBCOMPTYPE = "";
|
||||
private final static String D_CF_RECONCILER = null;
|
||||
|
|
@ -837,6 +836,7 @@ public class CassandraServer implements Cassandra {
|
|||
cf_def.row_cache_size == null ? CFMetaData.DEFAULT_ROW_CACHE_SIZE : cf_def.row_cache_size,
|
||||
cf_def.key_cache_size == null ? CFMetaData.DEFAULT_KEY_CACHE_SIZE : cf_def.key_cache_size,
|
||||
cf_def.read_repair_chance == null ? CFMetaData.DEFAULT_READ_REPAIR_CHANCE : cf_def.read_repair_chance,
|
||||
cf_def.replicate_on_write == null ? CFMetaData.DEFAULT_REPLICATE_ON_WRITE : cf_def.replicate_on_write,
|
||||
cf_def.gc_grace_seconds != null ? cf_def.gc_grace_seconds : CFMetaData.DEFAULT_GC_GRACE_SECONDS,
|
||||
DatabaseDescriptor.getComparator(validate),
|
||||
cf_def.min_compaction_threshold == null ? CFMetaData.DEFAULT_MIN_COMPACTION_THRESHOLD : cf_def.min_compaction_threshold,
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ public enum Stage
|
|||
ANTI_ENTROPY,
|
||||
MIGRATION,
|
||||
MISC,
|
||||
INTERNAL_RESPONSE;
|
||||
INTERNAL_RESPONSE,
|
||||
REPLICATE_ON_WRITE;
|
||||
|
||||
public String getJmxType()
|
||||
{
|
||||
|
|
@ -47,6 +48,7 @@ public enum Stage
|
|||
case MUTATION:
|
||||
case READ:
|
||||
case REQUEST_RESPONSE:
|
||||
case REPLICATE_ON_WRITE:
|
||||
return "request";
|
||||
default:
|
||||
throw new AssertionError("Unknown stage " + this);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import static org.apache.cassandra.config.DatabaseDescriptor.getConcurrentReaders;
|
||||
import static org.apache.cassandra.config.DatabaseDescriptor.getConcurrentWriters;
|
||||
import static org.apache.cassandra.config.DatabaseDescriptor.getConcurrentReplicators;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -44,6 +45,7 @@ public class StageManager
|
|||
stages.put(Stage.READ, multiThreadedConfigurableStage(Stage.READ, getConcurrentReaders()));
|
||||
stages.put(Stage.REQUEST_RESPONSE, multiThreadedStage(Stage.REQUEST_RESPONSE, Math.max(2, Runtime.getRuntime().availableProcessors())));
|
||||
stages.put(Stage.INTERNAL_RESPONSE, multiThreadedStage(Stage.INTERNAL_RESPONSE, Math.max(2, Runtime.getRuntime().availableProcessors())));
|
||||
stages.put(Stage.REPLICATE_ON_WRITE, multiThreadedConfigurableStage(Stage.REPLICATE_ON_WRITE, getConcurrentReplicators()));
|
||||
// the rest are all single-threaded
|
||||
stages.put(Stage.STREAM, new JMXEnabledThreadPoolExecutor(Stage.STREAM));
|
||||
stages.put(Stage.GOSSIP, new JMXEnabledThreadPoolExecutor(Stage.GOSSIP));
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ public final class CFMetaData
|
|||
public final static double DEFAULT_ROW_CACHE_SIZE = 0.0;
|
||||
public final static double DEFAULT_KEY_CACHE_SIZE = 200000;
|
||||
public final static double DEFAULT_READ_REPAIR_CHANCE = 1.0;
|
||||
public final static boolean DEFAULT_REPLICATE_ON_WRITE = true;
|
||||
public final static int DEFAULT_ROW_CACHE_SAVE_PERIOD_IN_SECONDS = 0;
|
||||
public final static int DEFAULT_KEY_CACHE_SAVE_PERIOD_IN_SECONDS = 3600;
|
||||
public final static int DEFAULT_GC_GRACE_SECONDS = 864000;
|
||||
|
|
@ -90,6 +91,7 @@ public final class CFMetaData
|
|||
0,
|
||||
0.01,
|
||||
0,
|
||||
false,
|
||||
0,
|
||||
BytesType.instance,
|
||||
DEFAULT_MIN_COMPACTION_THRESHOLD,
|
||||
|
|
@ -155,6 +157,7 @@ public final class CFMetaData
|
|||
private double rowCacheSize; // default 0
|
||||
private double keyCacheSize; // default 0.01
|
||||
private double readRepairChance; // default 1.0 (always), chance [0.0,1.0] of read repair
|
||||
private boolean replicateOnWrite; // default false
|
||||
private int gcGraceSeconds; // default 864000 (ten days)
|
||||
private AbstractType defaultValidator; // default none, use comparator types
|
||||
private Integer minCompactionThreshold; // default 4
|
||||
|
|
@ -177,6 +180,7 @@ public final class CFMetaData
|
|||
double rowCacheSize,
|
||||
double keyCacheSize,
|
||||
double readRepairChance,
|
||||
boolean replicateOnWrite,
|
||||
int gcGraceSeconds,
|
||||
AbstractType defaultValidator,
|
||||
int minCompactionThreshold,
|
||||
|
|
@ -204,6 +208,7 @@ public final class CFMetaData
|
|||
this.rowCacheSize = rowCacheSize;
|
||||
this.keyCacheSize = keyCacheSize;
|
||||
this.readRepairChance = readRepairChance;
|
||||
this.replicateOnWrite = replicateOnWrite;
|
||||
this.gcGraceSeconds = gcGraceSeconds;
|
||||
this.defaultValidator = defaultValidator;
|
||||
this.minCompactionThreshold = minCompactionThreshold;
|
||||
|
|
@ -242,6 +247,7 @@ public final class CFMetaData
|
|||
double rowCacheSize,
|
||||
double keyCacheSize,
|
||||
double readRepairChance,
|
||||
boolean replicateOnWrite,
|
||||
int gcGraceSeconds,
|
||||
AbstractType defaultValidator,
|
||||
int minCompactionThreshold,
|
||||
|
|
@ -263,6 +269,7 @@ public final class CFMetaData
|
|||
rowCacheSize,
|
||||
keyCacheSize,
|
||||
readRepairChance,
|
||||
replicateOnWrite,
|
||||
gcGraceSeconds,
|
||||
defaultValidator,
|
||||
minCompactionThreshold,
|
||||
|
|
@ -287,6 +294,7 @@ public final class CFMetaData
|
|||
0,
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
DEFAULT_GC_GRACE_SECONDS,
|
||||
BytesType.instance,
|
||||
DEFAULT_MIN_COMPACTION_THRESHOLD,
|
||||
|
|
@ -311,6 +319,7 @@ public final class CFMetaData
|
|||
cfm.rowCacheSize,
|
||||
cfm.keyCacheSize,
|
||||
cfm.readRepairChance,
|
||||
cfm.replicateOnWrite,
|
||||
cfm.gcGraceSeconds,
|
||||
cfm.defaultValidator,
|
||||
cfm.minCompactionThreshold,
|
||||
|
|
@ -336,6 +345,7 @@ public final class CFMetaData
|
|||
cfm.rowCacheSize,
|
||||
cfm.keyCacheSize,
|
||||
cfm.readRepairChance,
|
||||
cfm.replicateOnWrite,
|
||||
cfm.gcGraceSeconds,
|
||||
cfm.defaultValidator,
|
||||
cfm.minCompactionThreshold,
|
||||
|
|
@ -369,6 +379,7 @@ public final class CFMetaData
|
|||
cf.row_cache_size = rowCacheSize;
|
||||
cf.key_cache_size = keyCacheSize;
|
||||
cf.read_repair_chance = readRepairChance;
|
||||
cf.replicate_on_write = replicateOnWrite;
|
||||
cf.gc_grace_seconds = gcGraceSeconds;
|
||||
cf.default_validation_class = new Utf8(defaultValidator.getClass().getName());
|
||||
cf.min_compaction_threshold = minCompactionThreshold;
|
||||
|
|
@ -428,6 +439,7 @@ public final class CFMetaData
|
|||
cf.row_cache_size,
|
||||
cf.key_cache_size,
|
||||
cf.read_repair_chance,
|
||||
cf.replicate_on_write,
|
||||
cf.gc_grace_seconds,
|
||||
validator,
|
||||
minct,
|
||||
|
|
@ -460,6 +472,11 @@ public final class CFMetaData
|
|||
{
|
||||
return readRepairChance;
|
||||
}
|
||||
|
||||
public boolean getReplicateOnWrite()
|
||||
{
|
||||
return replicateOnWrite;
|
||||
}
|
||||
|
||||
public int getGcGraceSeconds()
|
||||
{
|
||||
|
|
@ -533,6 +550,7 @@ public final class CFMetaData
|
|||
.append(rowCacheSize, rhs.rowCacheSize)
|
||||
.append(keyCacheSize, rhs.keyCacheSize)
|
||||
.append(readRepairChance, rhs.readRepairChance)
|
||||
.append(replicateOnWrite, rhs.replicateOnWrite)
|
||||
.append(gcGraceSeconds, rhs.gcGraceSeconds)
|
||||
.append(minCompactionThreshold, rhs.minCompactionThreshold)
|
||||
.append(maxCompactionThreshold, rhs.maxCompactionThreshold)
|
||||
|
|
@ -558,6 +576,7 @@ public final class CFMetaData
|
|||
.append(rowCacheSize)
|
||||
.append(keyCacheSize)
|
||||
.append(readRepairChance)
|
||||
.append(replicateOnWrite)
|
||||
.append(gcGraceSeconds)
|
||||
.append(defaultValidator)
|
||||
.append(minCompactionThreshold)
|
||||
|
|
@ -654,6 +673,7 @@ public final class CFMetaData
|
|||
rowCacheSize = cf_def.row_cache_size;
|
||||
keyCacheSize = cf_def.key_cache_size;
|
||||
readRepairChance = cf_def.read_repair_chance;
|
||||
replicateOnWrite = cf_def.replicate_on_write;
|
||||
gcGraceSeconds = cf_def.gc_grace_seconds;
|
||||
defaultValidator = DatabaseDescriptor.getComparator(cf_def.default_validation_class);
|
||||
minCompactionThreshold = cf_def.min_compaction_threshold;
|
||||
|
|
@ -716,6 +736,7 @@ public final class CFMetaData
|
|||
def.setRow_cache_size(cfm.rowCacheSize);
|
||||
def.setKey_cache_size(cfm.keyCacheSize);
|
||||
def.setRead_repair_chance(cfm.readRepairChance);
|
||||
def.setReplicate_on_write(cfm.replicateOnWrite);
|
||||
def.setGc_grace_seconds(cfm.gcGraceSeconds);
|
||||
def.setDefault_validation_class(cfm.defaultValidator.getClass().getName());
|
||||
def.setMin_compaction_threshold(cfm.minCompactionThreshold);
|
||||
|
|
@ -757,6 +778,7 @@ public final class CFMetaData
|
|||
def.row_cache_size = cfm.rowCacheSize;
|
||||
def.key_cache_size = cfm.keyCacheSize;
|
||||
def.read_repair_chance = cfm.readRepairChance;
|
||||
def.replicate_on_write = cfm.replicateOnWrite;
|
||||
def.gc_grace_seconds = cfm.gcGraceSeconds;
|
||||
def.default_validation_class = cfm.defaultValidator == null ? null : cfm.defaultValidator.getClass().getName();
|
||||
def.min_compaction_threshold = cfm.minCompactionThreshold;
|
||||
|
|
@ -799,6 +821,7 @@ public final class CFMetaData
|
|||
newDef.memtable_throughput_in_mb = def.getMemtable_throughput_in_mb();
|
||||
newDef.min_compaction_threshold = def.getMin_compaction_threshold();
|
||||
newDef.read_repair_chance = def.getRead_repair_chance();
|
||||
newDef.replicate_on_write = def.isReplicate_on_write();
|
||||
newDef.row_cache_save_period_in_seconds = def.getRow_cache_save_period_in_seconds();
|
||||
newDef.row_cache_size = def.getRow_cache_size();
|
||||
newDef.subcomparator_type = def.getSubcomparator_type();
|
||||
|
|
@ -917,6 +940,7 @@ public final class CFMetaData
|
|||
.append("rowCacheSize", rowCacheSize)
|
||||
.append("keyCacheSize", keyCacheSize)
|
||||
.append("readRepairChance", readRepairChance)
|
||||
.append("replicateOnWrite", replicateOnWrite)
|
||||
.append("gcGraceSeconds", gcGraceSeconds)
|
||||
.append("defaultValidator", defaultValidator)
|
||||
.append("minCompactionThreshold", minCompactionThreshold)
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ public class Config
|
|||
|
||||
public Integer concurrent_reads = 8;
|
||||
public Integer concurrent_writes = 32;
|
||||
public Integer concurrent_replicates = 32;
|
||||
|
||||
public Integer memtable_flush_writers = null; // will get set to the length of data dirs in DatabaseDescriptor
|
||||
|
||||
|
|
|
|||
|
|
@ -224,6 +224,11 @@ public class DatabaseDescriptor
|
|||
throw new ConfigurationException("concurrent_writes must be at least 2");
|
||||
}
|
||||
|
||||
if (conf.concurrent_replicates != null && conf.concurrent_replicates < 2)
|
||||
{
|
||||
throw new ConfigurationException("conf.concurrent_replicates must be at least 2");
|
||||
}
|
||||
|
||||
/* Memtable flush writer threads */
|
||||
if (conf.memtable_flush_writers != null && conf.memtable_flush_writers < 1)
|
||||
{
|
||||
|
|
@ -613,6 +618,7 @@ public class DatabaseDescriptor
|
|||
cf.rows_cached,
|
||||
cf.keys_cached,
|
||||
cf.read_repair_chance,
|
||||
cf.replicate_on_write,
|
||||
cf.gc_grace_seconds,
|
||||
default_validator,
|
||||
cf.min_compaction_threshold,
|
||||
|
|
@ -841,6 +847,11 @@ public class DatabaseDescriptor
|
|||
return conf.concurrent_writes;
|
||||
}
|
||||
|
||||
public static int getConcurrentReplicators()
|
||||
{
|
||||
return conf.concurrent_replicates;
|
||||
}
|
||||
|
||||
public static int getFlushWriters()
|
||||
{
|
||||
return conf.memtable_flush_writers;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ public class RawColumnFamily
|
|||
public double rows_cached = CFMetaData.DEFAULT_ROW_CACHE_SIZE;
|
||||
public double keys_cached = CFMetaData.DEFAULT_KEY_CACHE_SIZE;
|
||||
public double read_repair_chance = CFMetaData.DEFAULT_READ_REPAIR_CHANCE;
|
||||
public boolean replicate_on_write = CFMetaData.DEFAULT_REPLICATE_ON_WRITE;
|
||||
public int gc_grace_seconds = CFMetaData.DEFAULT_GC_GRACE_SECONDS;
|
||||
public String default_validation_class;
|
||||
public int min_compaction_threshold = CFMetaData.DEFAULT_MIN_COMPACTION_THRESHOLD;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import org.apache.cassandra.config.CFMetaData;
|
|||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.db.filter.QueryPath;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.AbstractCommutativeType;
|
||||
import org.apache.cassandra.io.ICompactSerializer2;
|
||||
import org.apache.cassandra.io.util.IIterableColumns;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
|
@ -154,18 +155,25 @@ public class ColumnFamily implements IColumnContainer, IIterableColumns
|
|||
|
||||
public void addColumn(QueryPath path, ByteBuffer value, long timestamp)
|
||||
{
|
||||
assert path.columnName != null : path;
|
||||
addColumn(path.superColumnName, new Column(path.columnName, value, timestamp));
|
||||
addColumn(path, value, timestamp, 0);
|
||||
}
|
||||
|
||||
public void addColumn(QueryPath path, ByteBuffer value, long timestamp, int timeToLive)
|
||||
{
|
||||
assert path.columnName != null : path;
|
||||
Column column;
|
||||
if (timeToLive > 0)
|
||||
column = new ExpiringColumn(path.columnName, value, timestamp, timeToLive);
|
||||
AbstractType defaultValidator = metadata().getDefaultValidator();
|
||||
if (!defaultValidator.isCommutative())
|
||||
{
|
||||
if (timeToLive > 0)
|
||||
column = new ExpiringColumn(path.columnName, value, timestamp, timeToLive);
|
||||
else
|
||||
column = new Column(path.columnName, value, timestamp);
|
||||
}
|
||||
else
|
||||
column = new Column(path.columnName, value, timestamp);
|
||||
{
|
||||
column = ((AbstractCommutativeType)defaultValidator).createColumn(path.columnName, value, timestamp);
|
||||
}
|
||||
addColumn(path.superColumnName, column);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import java.util.*;
|
|||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
|
|
@ -292,6 +293,42 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean
|
|||
return keys;
|
||||
}
|
||||
|
||||
public boolean reverseReadWriteOrder()
|
||||
{
|
||||
//XXX: PURPOSE: allow less harmful race condition w/o locking
|
||||
|
||||
// normal read/write order (non-commutative):
|
||||
// purpose:
|
||||
// avoid missing an MT; may double reconcile
|
||||
// read path order:
|
||||
// 1) live MT
|
||||
// 2) MTs pending flush
|
||||
// 3) SSTs
|
||||
// write path order: (live MT => MT pending flush)
|
||||
// 1) add live MT to MTs pending flush
|
||||
// 2) reset live MT
|
||||
// write path order: (MT pending flush => SST)
|
||||
// 1) add SST
|
||||
// 2) remove MT pending flush
|
||||
|
||||
// reversed read/write order (commutative):
|
||||
// purpose:
|
||||
// avoid over-counting an MT; may miss an MT
|
||||
// read path order:
|
||||
// 1) SSTs
|
||||
// 2) MTs pending flush
|
||||
// 3) live MT
|
||||
// write path order: (live MT => MT pending flush)
|
||||
// 1) save live MT
|
||||
// 2) reset live MT
|
||||
// 3) add saved MT to MTs pending flush
|
||||
// write path order: (MT pending flush => SST)
|
||||
// 1) remove MT pending flush
|
||||
// 2) add SST
|
||||
|
||||
return metadata.getDefaultValidator().isCommutative();
|
||||
}
|
||||
|
||||
public void addIndex(final ColumnDefinition info)
|
||||
{
|
||||
assert info.getIndexType() != null;
|
||||
|
|
@ -650,8 +687,19 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean
|
|||
final CountDownLatch latch = new CountDownLatch(icc.size());
|
||||
for (ColumnFamilyStore cfs : icc)
|
||||
{
|
||||
submitFlush(cfs.memtable, latch);
|
||||
cfs.memtable = new Memtable(cfs);
|
||||
if (!reverseReadWriteOrder())
|
||||
{
|
||||
//XXX: race condition: may allow double reconcile; but never misses an MT
|
||||
submitFlush(cfs.memtable, latch);
|
||||
cfs.memtable = new Memtable(cfs);
|
||||
}
|
||||
else
|
||||
{
|
||||
//XXX: race condition: may miss an MT, but no double counts
|
||||
Memtable pendingFlush = cfs.memtable;
|
||||
cfs.memtable = new Memtable(cfs);
|
||||
submitFlush(pendingFlush, latch);
|
||||
}
|
||||
}
|
||||
|
||||
// when all the memtables have been written, including for indexes, mark the flush in the commitlog header.
|
||||
|
|
@ -793,7 +841,6 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean
|
|||
// remove columns if
|
||||
// (a) the column itself is tombstoned or
|
||||
// (b) the CF is tombstoned and the column is not newer than it
|
||||
// (we split the test to avoid computing ClockRelationship if not necessary)
|
||||
if ((c.isMarkedForDelete() && c.getLocalDeletionTime() <= gcBefore)
|
||||
|| c.timestamp() <= cf.getMarkedForDeleteAt())
|
||||
{
|
||||
|
|
@ -1180,36 +1227,75 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean
|
|||
{
|
||||
IColumnIterator iter;
|
||||
|
||||
/* add the current memtable */
|
||||
iter = filter.getMemtableColumnIterator(getMemtableThreadSafe(), getComparator());
|
||||
if (iter != null)
|
||||
int sstablesToIterate = 0;
|
||||
if (!reverseReadWriteOrder())
|
||||
{
|
||||
returnCF.delete(iter.getColumnFamily());
|
||||
|
||||
iterators.add(iter);
|
||||
}
|
||||
//XXX: race condition: may allow double reconcile; but never misses an MT
|
||||
|
||||
/* add the memtables being flushed */
|
||||
for (Memtable memtable : memtablesPendingFlush)
|
||||
{
|
||||
iter = filter.getMemtableColumnIterator(memtable, getComparator());
|
||||
/* add the current memtable */
|
||||
iter = filter.getMemtableColumnIterator(getMemtableThreadSafe(), getComparator());
|
||||
if (iter != null)
|
||||
{
|
||||
returnCF.delete(iter.getColumnFamily());
|
||||
iterators.add(iter);
|
||||
}
|
||||
}
|
||||
|
||||
/* add the SSTables on disk */
|
||||
int sstablesToIterate = 0;
|
||||
for (SSTableReader sstable : ssTables)
|
||||
/* add the memtables being flushed */
|
||||
for (Memtable memtable : memtablesPendingFlush)
|
||||
{
|
||||
iter = filter.getMemtableColumnIterator(memtable, getComparator());
|
||||
if (iter != null)
|
||||
{
|
||||
returnCF.delete(iter.getColumnFamily());
|
||||
iterators.add(iter);
|
||||
}
|
||||
}
|
||||
|
||||
/* add the SSTables on disk */
|
||||
for (SSTableReader sstable : ssTables)
|
||||
{
|
||||
iter = filter.getSSTableColumnIterator(sstable);
|
||||
if (iter.getColumnFamily() != null)
|
||||
{
|
||||
returnCF.delete(iter.getColumnFamily());
|
||||
iterators.add(iter);
|
||||
}
|
||||
sstablesToIterate++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
iter = filter.getSSTableColumnIterator(sstable);
|
||||
if (iter.getColumnFamily() != null)
|
||||
//XXX: race condition: may miss an MT, but no double counts
|
||||
|
||||
/* add the SSTables on disk */
|
||||
for (SSTableReader sstable : ssTables)
|
||||
{
|
||||
iter = filter.getSSTableColumnIterator(sstable);
|
||||
if (iter.getColumnFamily() != null)
|
||||
{
|
||||
returnCF.delete(iter.getColumnFamily());
|
||||
iterators.add(iter);
|
||||
}
|
||||
sstablesToIterate++;
|
||||
}
|
||||
|
||||
/* add the memtables being flushed */
|
||||
for (Memtable memtable : memtablesPendingFlush)
|
||||
{
|
||||
iter = filter.getMemtableColumnIterator(memtable, getComparator());
|
||||
if (iter != null)
|
||||
{
|
||||
returnCF.delete(iter.getColumnFamily());
|
||||
iterators.add(iter);
|
||||
}
|
||||
}
|
||||
|
||||
/* add the current memtable */
|
||||
iter = filter.getMemtableColumnIterator(getMemtableThreadSafe(), getComparator());
|
||||
if (iter != null)
|
||||
{
|
||||
returnCF.delete(iter.getColumnFamily());
|
||||
iterators.add(iter);
|
||||
sstablesToIterate++;
|
||||
}
|
||||
}
|
||||
recentSSTablesPerRead.add(sstablesToIterate);
|
||||
|
|
@ -1270,12 +1356,23 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean
|
|||
|
||||
QueryFilter filter = new QueryFilter(null, new QueryPath(columnFamily, superColumn, null), columnFilter);
|
||||
Collection<Memtable> memtables = new ArrayList<Memtable>();
|
||||
memtables.add(getMemtableThreadSafe());
|
||||
memtables.addAll(memtablesPendingFlush);
|
||||
|
||||
Collection<SSTableReader> sstables = new ArrayList<SSTableReader>();
|
||||
Iterables.addAll(sstables, ssTables);
|
||||
|
||||
if (!reverseReadWriteOrder())
|
||||
{
|
||||
//XXX: race condition: may allow double reconcile; but never misses an MT
|
||||
memtables.add(getMemtableThreadSafe());
|
||||
memtables.addAll(memtablesPendingFlush);
|
||||
Iterables.addAll(sstables, ssTables);
|
||||
}
|
||||
else
|
||||
{
|
||||
//XXX: race condition: may miss an MT, but no double counts
|
||||
Iterables.addAll(sstables, ssTables);
|
||||
memtables.addAll(memtablesPendingFlush);
|
||||
memtables.add(getMemtableThreadSafe());
|
||||
}
|
||||
|
||||
RowIterator iterator = RowIteratorFactory.getIterator(memtables, sstables, startWith, stopAt, filter, getComparator(), this);
|
||||
int gcBefore = (int)(System.currentTimeMillis() / 1000) - metadata.getGcGraceSeconds();
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import java.io.DataInput;
|
|||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
@ -35,9 +36,10 @@ import org.apache.cassandra.utils.FBUtilities;
|
|||
public class ColumnSerializer implements ICompactSerializer2<IColumn>
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(ColumnSerializer.class);
|
||||
|
||||
|
||||
public final static int DELETION_MASK = 0x01;
|
||||
public final static int EXPIRATION_MASK = 0x02;
|
||||
public final static int COUNTER_MASK = 0x04;
|
||||
|
||||
public void serialize(IColumn column, DataOutput dos)
|
||||
{
|
||||
|
|
@ -45,12 +47,21 @@ public class ColumnSerializer implements ICompactSerializer2<IColumn>
|
|||
FBUtilities.writeShortByteArray(column.name(), dos);
|
||||
try
|
||||
{
|
||||
if (column instanceof ExpiringColumn) {
|
||||
dos.writeByte(EXPIRATION_MASK);
|
||||
dos.writeInt(((ExpiringColumn) column).getTimeToLive());
|
||||
dos.writeInt(column.getLocalDeletionTime());
|
||||
} else {
|
||||
dos.writeByte((column.isMarkedForDelete()) ? DELETION_MASK : 0);
|
||||
if (column instanceof CounterColumn)
|
||||
{
|
||||
dos.writeByte(COUNTER_MASK);
|
||||
dos.writeLong(((CounterColumn)column).timestampOfLastDelete());
|
||||
FBUtilities.writeShortByteArray(ByteBuffer.wrap(((CounterColumn)column).partitionedCounter()), dos);
|
||||
}
|
||||
else if (column instanceof ExpiringColumn)
|
||||
{
|
||||
dos.writeByte(EXPIRATION_MASK);
|
||||
dos.writeInt(((ExpiringColumn) column).getTimeToLive());
|
||||
dos.writeInt(column.getLocalDeletionTime());
|
||||
}
|
||||
else
|
||||
{
|
||||
dos.writeByte((column.isMarkedForDelete()) ? DELETION_MASK : 0);
|
||||
}
|
||||
dos.writeLong(column.timestamp());
|
||||
FBUtilities.writeByteArray(column.value(), dos);
|
||||
|
|
@ -68,7 +79,16 @@ public class ColumnSerializer implements ICompactSerializer2<IColumn>
|
|||
throw new CorruptColumnException("invalid column name length " + name.remaining());
|
||||
|
||||
int b = dis.readUnsignedByte();
|
||||
if ((b & EXPIRATION_MASK) != 0)
|
||||
if ((b & COUNTER_MASK) != 0)
|
||||
{
|
||||
long timestampOfLastDelete = dis.readLong();
|
||||
ByteBuffer pc = FBUtilities.readShortByteArray(dis);
|
||||
byte[] partitionedCounter = Arrays.copyOfRange(pc.array(), pc.position() + pc.arrayOffset(), pc.limit());
|
||||
long timestamp = dis.readLong();
|
||||
ByteBuffer value = FBUtilities.readByteArray(dis);
|
||||
return new CounterColumn(name, value, timestamp, partitionedCounter, timestampOfLastDelete);
|
||||
}
|
||||
else if ((b & EXPIRATION_MASK) != 0)
|
||||
{
|
||||
int ttl = dis.readInt();
|
||||
int expiration = dis.readInt();
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ import org.apache.cassandra.io.sstable.*;
|
|||
import org.apache.cassandra.io.util.FileUtils;
|
||||
import org.apache.cassandra.service.AntiEntropyService;
|
||||
import org.apache.cassandra.service.StorageService;
|
||||
import org.apache.cassandra.streaming.OperationType;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.Pair;
|
||||
import org.cliffc.high_scale_lib.NonBlockingHashMap;
|
||||
|
|
@ -595,11 +596,11 @@ public class CompactionManager implements CompactionManagerMBean
|
|||
else
|
||||
return executor.submit(runnable);
|
||||
}
|
||||
|
||||
public Future<SSTableReader> submitSSTableBuild(Descriptor desc)
|
||||
|
||||
public Future<SSTableReader> submitSSTableBuild(Descriptor desc, OperationType type)
|
||||
{
|
||||
// invalid descriptions due to missing or dropped CFS are handled by SSTW and StreamInSession.
|
||||
final SSTableWriter.Builder builder = SSTableWriter.createBuilder(desc);
|
||||
final SSTableWriter.Builder builder = SSTableWriter.createBuilder(desc, type);
|
||||
Callable<SSTableReader> callable = new Callable<SSTableReader>()
|
||||
{
|
||||
public SSTableReader call() throws IOException
|
||||
|
|
|
|||
|
|
@ -0,0 +1,287 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.apache.cassandra.db;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import org.apache.cassandra.db.context.CounterContext;
|
||||
import org.apache.cassandra.db.context.IContext.ContextRelationship;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.io.util.DataOutputBuffer;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
||||
/**
|
||||
* A column that represents a partitioned counter.
|
||||
*/
|
||||
public class CounterColumn extends Column
|
||||
{
|
||||
private static Logger logger = Logger.getLogger(CounterColumn.class);
|
||||
|
||||
private static CounterContext contextManager = CounterContext.instance();
|
||||
|
||||
protected ByteBuffer value; // NOT final: delta OR total of partitioned counter
|
||||
protected byte[] partitionedCounter; // NOT final: only modify inline, carefully
|
||||
protected final long timestampOfLastDelete;
|
||||
|
||||
public CounterColumn(ByteBuffer name, ByteBuffer value, long timestamp)
|
||||
{
|
||||
this(name, value, timestamp, contextManager.create());
|
||||
}
|
||||
|
||||
public CounterColumn(ByteBuffer name, ByteBuffer value, long timestamp, byte[] partitionedCounter)
|
||||
{
|
||||
this(name, value, timestamp, partitionedCounter, Long.MIN_VALUE);
|
||||
}
|
||||
|
||||
public CounterColumn(ByteBuffer name, ByteBuffer value, long timestamp, byte[] partitionedCounter, long timestampOfLastDelete)
|
||||
{
|
||||
super(name, FBUtilities.EMPTY_BYTE_BUFFER, timestamp);
|
||||
this.value = value;
|
||||
this.partitionedCounter = partitionedCounter;
|
||||
this.timestampOfLastDelete = timestampOfLastDelete;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer value()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
public byte[] partitionedCounter()
|
||||
{
|
||||
return partitionedCounter;
|
||||
}
|
||||
|
||||
public long timestampOfLastDelete()
|
||||
{
|
||||
return timestampOfLastDelete;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size()
|
||||
{
|
||||
/*
|
||||
* An expired column adds to a Column :
|
||||
* 4 bytes for length of partitionedCounter
|
||||
* + length of partitionedCounter
|
||||
* + 8 bytes for timestampOfLastDelete
|
||||
*/
|
||||
return super.size() + DBConstants.intSize_ + partitionedCounter.length + DBConstants.tsSize_;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IColumn diff(IColumn column)
|
||||
{
|
||||
assert column instanceof CounterColumn : "Wrong class type.";
|
||||
|
||||
if (timestamp() < column.timestamp())
|
||||
return column;
|
||||
if (timestampOfLastDelete() < ((CounterColumn)column).timestampOfLastDelete())
|
||||
return column;
|
||||
ContextRelationship rel = contextManager.diff(
|
||||
((CounterColumn)column).partitionedCounter(),
|
||||
partitionedCounter());
|
||||
if (ContextRelationship.GREATER_THAN == rel || ContextRelationship.DISJOINT == rel)
|
||||
return column;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDigest(MessageDigest digest)
|
||||
{
|
||||
digest.update(name.array(),name.position()+name.arrayOffset(),name.remaining());
|
||||
digest.update(value.array(),value.position()+name.arrayOffset(),value.remaining());
|
||||
digest.update(FBUtilities.toByteArray(timestamp));
|
||||
digest.update(partitionedCounter);
|
||||
digest.update(FBUtilities.toByteArray(timestampOfLastDelete));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IColumn reconcile(IColumn column)
|
||||
{
|
||||
assert (column instanceof CounterColumn) || (column instanceof DeletedColumn) : "Wrong class type.";
|
||||
|
||||
if (isMarkedForDelete())
|
||||
{
|
||||
if (column.isMarkedForDelete()) // tombstone + tombstone: keep later tombstone
|
||||
{
|
||||
return timestamp() > column.timestamp() ? this : column;
|
||||
}
|
||||
else // tombstone + live: track last tombstone
|
||||
{
|
||||
if (timestamp() > column.timestamp()) // tombstone > live
|
||||
{
|
||||
return this;
|
||||
}
|
||||
// tombstone <= live last delete
|
||||
if (timestamp() <= ((CounterColumn)column).timestampOfLastDelete())
|
||||
{
|
||||
return column;
|
||||
}
|
||||
// tombstone > live last delete
|
||||
return new CounterColumn(
|
||||
column.name(),
|
||||
column.value(),
|
||||
column.timestamp(),
|
||||
((CounterColumn)column).partitionedCounter(),
|
||||
timestamp());
|
||||
}
|
||||
}
|
||||
else if (column.isMarkedForDelete()) // live + tombstone: track last tombstone
|
||||
{
|
||||
if (timestamp() < column.timestamp()) // live < tombstone
|
||||
{
|
||||
return column;
|
||||
}
|
||||
// live last delete >= tombstone
|
||||
if (timestampOfLastDelete() >= column.timestamp())
|
||||
{
|
||||
return this;
|
||||
}
|
||||
// live last delete < tombstone
|
||||
return new CounterColumn(
|
||||
name(),
|
||||
value(),
|
||||
timestamp(),
|
||||
partitionedCounter(),
|
||||
column.timestamp());
|
||||
}
|
||||
// live + live: merge clocks; update value
|
||||
byte[] mergedPartitionedCounter = contextManager.merge(
|
||||
partitionedCounter(),
|
||||
((CounterColumn)column).partitionedCounter());
|
||||
ByteBuffer byteBufferValue;
|
||||
if (0 == mergedPartitionedCounter.length)
|
||||
{
|
||||
long mergedValue = value().getLong(value().arrayOffset()) +
|
||||
column.value().getLong(column.value().arrayOffset());
|
||||
byteBufferValue = FBUtilities.toByteBuffer(mergedValue);
|
||||
} else
|
||||
byteBufferValue = ByteBuffer.wrap(contextManager.total(mergedPartitionedCounter));
|
||||
return new CounterColumn(
|
||||
name(),
|
||||
byteBufferValue,
|
||||
Math.max(timestamp(), column.timestamp()),
|
||||
mergedPartitionedCounter,
|
||||
Math.max(timestampOfLastDelete(), ((CounterColumn)column).timestampOfLastDelete()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
|
||||
CounterColumn column = (CounterColumn)o;
|
||||
|
||||
if (timestamp != column.timestamp)
|
||||
return false;
|
||||
|
||||
if (timestampOfLastDelete != column.timestampOfLastDelete)
|
||||
return false;
|
||||
|
||||
if (!Arrays.equals(partitionedCounter, column.partitionedCounter))
|
||||
return false;
|
||||
|
||||
if (!name.equals(column.name))
|
||||
return false;
|
||||
|
||||
return value.equals(column.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + (partitionedCounter != null ? Arrays.hashCode(partitionedCounter) : 0);
|
||||
result = 31 * result + (int)(timestampOfLastDelete ^ (timestampOfLastDelete >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IColumn deepCopy()
|
||||
{
|
||||
return new CounterColumn(
|
||||
ByteBufferUtil.clone(name),
|
||||
ByteBufferUtil.clone(value),
|
||||
timestamp,
|
||||
partitionedCounter,
|
||||
timestampOfLastDelete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(AbstractType comparator)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(comparator.getString(name));
|
||||
sb.append(":");
|
||||
sb.append(isMarkedForDelete());
|
||||
sb.append(":");
|
||||
sb.append(value.getLong(value.arrayOffset()));
|
||||
sb.append("@");
|
||||
sb.append(timestamp());
|
||||
sb.append("!");
|
||||
sb.append(timestampOfLastDelete);
|
||||
sb.append("@");
|
||||
sb.append(contextManager.toString(partitionedCounter));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void updateValue()
|
||||
{
|
||||
value = ByteBuffer.wrap(contextManager.total(partitionedCounter));
|
||||
}
|
||||
|
||||
public void update(InetAddress node)
|
||||
{
|
||||
long delta = value.getLong(value.arrayOffset());
|
||||
partitionedCounter = contextManager.update(partitionedCounter, node, delta);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
public CounterColumn cleanNodeCounts(InetAddress node)
|
||||
{
|
||||
//XXX: inline modification non-destructive; cases:
|
||||
// 1) AES post-stream
|
||||
// 2) RRR, after CF.cloneMe()
|
||||
// 3) RRR, after CF.diff() which creates a new CF
|
||||
byte[] cleanPartitionedCounter = contextManager.cleanNodeCounts(partitionedCounter, node);
|
||||
if (cleanPartitionedCounter == partitionedCounter)
|
||||
return this;
|
||||
if (0 == cleanPartitionedCounter.length)
|
||||
return null;
|
||||
return new CounterColumn(
|
||||
name,
|
||||
ByteBuffer.wrap(contextManager.total(cleanPartitionedCounter)),
|
||||
timestamp,
|
||||
cleanPartitionedCounter,
|
||||
timestampOfLastDelete
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -56,6 +56,14 @@ public class DeletedColumn extends Column
|
|||
{
|
||||
return value.getInt(value.position()+value.arrayOffset() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IColumn reconcile(IColumn column)
|
||||
{
|
||||
if (column instanceof DeletedColumn)
|
||||
return super.reconcile(column);
|
||||
return column.reconcile(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IColumn deepCopy()
|
||||
|
|
|
|||
|
|
@ -20,15 +20,20 @@ package org.apache.cassandra.db;
|
|||
*
|
||||
*/
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
|
||||
public interface IColumnContainer
|
||||
{
|
||||
public void addColumn(IColumn column);
|
||||
public void remove(ByteBuffer columnName);
|
||||
|
||||
public boolean isMarkedForDelete();
|
||||
public long getMarkedForDeleteAt();
|
||||
|
||||
public AbstractType getComparator();
|
||||
|
||||
public Collection<IColumn> getSortedColumns();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,8 +171,18 @@ public class Memtable implements Comparable<Memtable>, IFlushable
|
|||
{
|
||||
public void runMayThrow() throws IOException
|
||||
{
|
||||
cfs.addSSTable(writeSortedContents());
|
||||
cfs.getMemtablesPendingFlush().remove(Memtable.this);
|
||||
if (!cfs.reverseReadWriteOrder())
|
||||
{
|
||||
//XXX: race condition: may allow double reconcile; but never misses an MT
|
||||
cfs.addSSTable(writeSortedContents());
|
||||
cfs.getMemtablesPendingFlush().remove(Memtable.this);
|
||||
}
|
||||
else
|
||||
{
|
||||
//XXX: race condition: may miss an MT, but no double counts
|
||||
cfs.getMemtablesPendingFlush().remove(Memtable.this);
|
||||
cfs.addSSTable(writeSortedContents());
|
||||
}
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,129 @@
|
|||
package org.apache.cassandra.db;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import org.apache.cassandra.db.filter.QueryPath;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.AbstractCommutativeType;
|
||||
import org.apache.cassandra.net.Message;
|
||||
import org.apache.cassandra.net.MessagingService;
|
||||
import org.apache.cassandra.service.StorageService;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
||||
public class ReplicateOnWriteTask implements Runnable
|
||||
{
|
||||
private RowMutation mutation;
|
||||
private static Logger logger = Logger.getLogger(ReplicateOnWriteTask.class);
|
||||
|
||||
public ReplicateOnWriteTask(RowMutation mutation)
|
||||
{
|
||||
this.mutation = mutation;
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
// construct SliceByNamesReadCommand for CFs to repair
|
||||
List<ReadCommand> readCommands = new LinkedList<ReadCommand>();
|
||||
for (ColumnFamily columnFamily : mutation.getColumnFamilies())
|
||||
{
|
||||
// filter out non-repair CFs
|
||||
if (!columnFamily.metadata().getReplicateOnWrite())
|
||||
continue;
|
||||
|
||||
// CF type: regular
|
||||
if (!columnFamily.isSuper())
|
||||
{
|
||||
QueryPath queryPath = new QueryPath(columnFamily.metadata().cfName);
|
||||
ReadCommand readCommand = new SliceByNamesReadCommand(
|
||||
mutation.getTable(),
|
||||
mutation.key(),
|
||||
queryPath,
|
||||
columnFamily.getColumnNames()
|
||||
);
|
||||
|
||||
readCommands.add(readCommand);
|
||||
continue;
|
||||
}
|
||||
|
||||
// CF type: super
|
||||
for (IColumn superColumn : columnFamily.getSortedColumns())
|
||||
{
|
||||
QueryPath queryPath = new QueryPath(columnFamily.metadata().cfName, superColumn.name());
|
||||
|
||||
// construct set of sub-column names
|
||||
Collection<IColumn> subColumns = superColumn.getSubColumns();
|
||||
Collection<ByteBuffer> subColNames = new HashSet<ByteBuffer>(subColumns.size());
|
||||
for (IColumn subCol : subColumns)
|
||||
{
|
||||
subColNames.add(subCol.name());
|
||||
}
|
||||
|
||||
ReadCommand readCommand = new SliceByNamesReadCommand(
|
||||
mutation.getTable(),
|
||||
mutation.key(),
|
||||
queryPath,
|
||||
subColNames
|
||||
);
|
||||
readCommands.add(readCommand);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == readCommands.size())
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
// send repair to non-local replicas
|
||||
List<InetAddress> foreignReplicas = StorageService.instance.getLiveNaturalEndpoints(
|
||||
mutation.getTable(),
|
||||
mutation.key()
|
||||
);
|
||||
foreignReplicas.remove(FBUtilities.getLocalAddress()); // remove local replica
|
||||
|
||||
// create a repair RowMutation
|
||||
RowMutation repairRowMutation = new RowMutation(mutation.getTable(), mutation.key());
|
||||
for (ReadCommand readCommand : readCommands)
|
||||
{
|
||||
Table table = Table.open(readCommand.table);
|
||||
Row row = readCommand.getRow(table);
|
||||
AbstractType defaultValidator = row.cf.metadata().getDefaultValidator();
|
||||
if (defaultValidator.isCommutative())
|
||||
{
|
||||
/**
|
||||
* Clean out contexts for all nodes we're sending the repair to, otherwise,
|
||||
* we could send a context which is local to one of the foreign replicas,
|
||||
* which would then incorrectly add that to its own count, because
|
||||
* local resolution aggregates.
|
||||
*/
|
||||
// note: the following logic could be optimized
|
||||
for (InetAddress foreignNode : foreignReplicas)
|
||||
{
|
||||
((AbstractCommutativeType)defaultValidator).cleanContext(row.cf, foreignNode);
|
||||
}
|
||||
}
|
||||
repairRowMutation.add(row.cf);
|
||||
}
|
||||
|
||||
// send repair to non-local replicas
|
||||
for (InetAddress foreignReplica : foreignReplicas)
|
||||
{
|
||||
RowMutationMessage repairMessage = new RowMutationMessage(
|
||||
repairRowMutation);
|
||||
Message message = repairMessage.makeRowMutationMessage(StorageService.Verb.REPLICATE_ON_WRITE);
|
||||
MessagingService.instance.sendOneWay(message, foreignReplica);
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.apache.cassandra.db;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.apache.cassandra.net.IVerbHandler;
|
||||
import org.apache.cassandra.net.Message;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
public class ReplicateOnWriteVerbHandler implements IVerbHandler
|
||||
{
|
||||
private static Logger logger = Logger.getLogger(ReplicateOnWriteVerbHandler.class);
|
||||
|
||||
public void doVerb(Message message)
|
||||
{
|
||||
byte[] body = message.getMessageBody();
|
||||
ByteArrayInputStream buffer = new ByteArrayInputStream(body);
|
||||
|
||||
try
|
||||
{
|
||||
RowMutationMessage rmMsg = RowMutationMessage.serializer().deserialize(new DataInputStream(buffer));
|
||||
RowMutation rm = rmMsg.getRowMutation();
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("repair-on-write for key " + FBUtilities.bytesToHex(rm.key()));
|
||||
rm.apply();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new IOError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -23,6 +23,9 @@ import java.io.ByteArrayOutputStream;
|
|||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
|
@ -43,6 +46,9 @@ import org.apache.cassandra.thrift.Deletion;
|
|||
import org.apache.cassandra.thrift.Mutation;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.AbstractCommutativeType;
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
public class RowMutation
|
||||
|
|
@ -316,7 +322,21 @@ public class RowMutation
|
|||
rm.delete(new QueryPath(cfName, del.super_column), del.timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the context of all CounterColumns in this RowMutation
|
||||
*/
|
||||
public void updateCommutativeTypes(InetAddress node)
|
||||
{
|
||||
for (ColumnFamily cf : modifications_.values())
|
||||
{
|
||||
AbstractType defaultValidator = cf.metadata().getDefaultValidator();
|
||||
if (!defaultValidator.isCommutative())
|
||||
continue;
|
||||
((AbstractCommutativeType)defaultValidator).update(cf, node);
|
||||
}
|
||||
}
|
||||
|
||||
static RowMutation fromBytes(byte[] raw) throws IOException
|
||||
{
|
||||
RowMutation rm = serializer_.deserialize(new DataInputStream(new ByteArrayInputStream(raw)));
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ import org.apache.cassandra.net.Message;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.cassandra.concurrent.Stage;
|
||||
import org.apache.cassandra.concurrent.StageManager;
|
||||
import org.apache.cassandra.net.*;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
|
@ -74,6 +76,10 @@ public class RowMutationVerbHandler implements IVerbHandler
|
|||
if (logger_.isDebugEnabled())
|
||||
logger_.debug(rm + " applied. Sending response to " + message.getMessageId() + "@" + message.getFrom());
|
||||
MessagingService.instance.sendOneWay(responseMessage, message.getFrom());
|
||||
|
||||
// repair-on-write (remote message)
|
||||
ReplicateOnWriteTask replicateOnWriteTask = new ReplicateOnWriteTask(rm);
|
||||
StageManager.getStage(Stage.REPLICATE_ON_WRITE).execute(replicateOnWriteTask);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -99,6 +99,11 @@ public class SuperColumn implements IColumn, IColumnContainer
|
|||
return columns_.values();
|
||||
}
|
||||
|
||||
public Collection<IColumn> getSortedColumns()
|
||||
{
|
||||
return getSubColumns();
|
||||
}
|
||||
|
||||
public IColumn getSubColumn(ByteBuffer columnName)
|
||||
{
|
||||
IColumn column = columns_.get(columnName);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,553 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
package org.apache.cassandra.db.context;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.cassandra.db.DBConstants;
|
||||
import org.apache.cassandra.db.context.IContext;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
|
||||
/**
|
||||
* An implementation of a partitioned counter context.
|
||||
*
|
||||
* The data structure is:
|
||||
* a vector of (node id, logical clock, count) tuples.
|
||||
*
|
||||
* On update, the node will:
|
||||
* 1) increment the logical clock, and
|
||||
* 2) update the count associated w/ its tuple.
|
||||
*
|
||||
* The logical clock represents the # of operations executed
|
||||
* by the node. The aggregated count can be determined
|
||||
* by rolling up all the counts from each tuple.
|
||||
*
|
||||
* NOTE: only a given node id may increment its associated count and
|
||||
* care must be taken to ensure that tuples are correctly made consistent.
|
||||
*/
|
||||
public class CounterContext implements IContext
|
||||
{
|
||||
private static final int idLength;
|
||||
private static final FBUtilities.ByteArrayWrapper idWrapper;
|
||||
private static final int clockLength = DBConstants.longSize_;
|
||||
private static final int countLength = DBConstants.longSize_;
|
||||
private static final int stepLength; // length: id + logical clock + count
|
||||
|
||||
// lazy-load singleton
|
||||
private static class LazyHolder
|
||||
{
|
||||
private static final CounterContext counterContext = new CounterContext();
|
||||
}
|
||||
|
||||
static
|
||||
{
|
||||
byte[] id = FBUtilities.getLocalAddress().getAddress();
|
||||
idLength = id.length;
|
||||
idWrapper = new FBUtilities.ByteArrayWrapper(id);
|
||||
stepLength = idLength + clockLength + countLength;
|
||||
}
|
||||
|
||||
public static CounterContext instance()
|
||||
{
|
||||
return LazyHolder.counterContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an initial counter context.
|
||||
*
|
||||
* @return an empty counter context.
|
||||
*/
|
||||
public byte[] create()
|
||||
{
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
// write a tuple (node id, clock, count) at the front
|
||||
protected static void writeElement(byte[] context, byte[] id, long clock, long count)
|
||||
{
|
||||
writeElementAtStepOffset(context, 0, id, clock, count);
|
||||
}
|
||||
|
||||
// write a tuple (node id, clock, count) at step offset
|
||||
protected static void writeElementAtStepOffset(byte[] context, int stepOffset, byte[] id, long clock, long count)
|
||||
{
|
||||
int offset = stepOffset * stepLength;
|
||||
System.arraycopy(id, 0, context, offset, idLength);
|
||||
FBUtilities.copyIntoBytes(context, offset + idLength, clock);
|
||||
FBUtilities.copyIntoBytes(context, offset + idLength + clockLength, count);
|
||||
}
|
||||
|
||||
public byte[] update(byte[] context, InetAddress node, long delta)
|
||||
{
|
||||
// calculate node id
|
||||
byte[] nodeId = node.getAddress();
|
||||
|
||||
// look for this node id
|
||||
for (int offset = 0; offset < context.length; offset += stepLength)
|
||||
{
|
||||
if (FBUtilities.compareByteSubArrays(nodeId, 0, context, offset, idLength) != 0)
|
||||
continue;
|
||||
|
||||
// node id found: increment clock, update count; shift to front
|
||||
long clock = FBUtilities.byteArrayToLong(context, offset + idLength);
|
||||
long count = FBUtilities.byteArrayToLong(context, offset + idLength + clockLength);
|
||||
|
||||
System.arraycopy(
|
||||
context,
|
||||
0,
|
||||
context,
|
||||
stepLength,
|
||||
offset);
|
||||
writeElement(context, nodeId, clock + 1L, count + delta);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
// node id not found: widen context
|
||||
byte[] previous = context;
|
||||
context = new byte[previous.length + stepLength];
|
||||
|
||||
writeElement(context, nodeId, 1L, delta);
|
||||
System.arraycopy(
|
||||
previous,
|
||||
0,
|
||||
context,
|
||||
stepLength,
|
||||
previous.length);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
// swap bytes of step length in context
|
||||
protected static void swapElement(byte[] context, int left, int right)
|
||||
{
|
||||
if (left == right) return;
|
||||
|
||||
byte temp;
|
||||
for (int i = 0; i < stepLength; i++)
|
||||
{
|
||||
temp = context[left+i];
|
||||
context[left+i] = context[right+i];
|
||||
context[right+i] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
// partition bytes of step length in context (for quicksort)
|
||||
protected static int partitionElements(byte[] context, int left, int right, int pivotIndex)
|
||||
{
|
||||
int leftOffset = left * stepLength;
|
||||
int rightOffset = right * stepLength;
|
||||
int pivotOffset = pivotIndex * stepLength;
|
||||
|
||||
byte[] pivotValue = ArrayUtils.subarray(context, pivotOffset, pivotOffset + stepLength);
|
||||
swapElement(context, pivotOffset, rightOffset);
|
||||
int storeOffset = leftOffset;
|
||||
for (int i = leftOffset; i < rightOffset; i += stepLength)
|
||||
{
|
||||
if (FBUtilities.compareByteSubArrays(context, i, pivotValue, 0, stepLength) <= 0)
|
||||
{
|
||||
swapElement(context, i, storeOffset);
|
||||
storeOffset += stepLength;
|
||||
}
|
||||
}
|
||||
swapElement(context, storeOffset, rightOffset);
|
||||
return storeOffset / stepLength;
|
||||
}
|
||||
|
||||
// quicksort helper
|
||||
protected static void sortElementsByIdHelper(byte[] context, int left, int right)
|
||||
{
|
||||
if (right <= left) return;
|
||||
|
||||
int pivotIndex = (left + right) / 2;
|
||||
int pivotIndexNew = partitionElements(context, left, right, pivotIndex);
|
||||
sortElementsByIdHelper(context, left, pivotIndexNew - 1);
|
||||
sortElementsByIdHelper(context, pivotIndexNew + 1, right);
|
||||
}
|
||||
|
||||
// quicksort context by id
|
||||
protected static byte[] sortElementsById(byte[] context)
|
||||
{
|
||||
assert 0 == (context.length % stepLength) : "context size is not correct.";
|
||||
sortElementsByIdHelper(
|
||||
context,
|
||||
0,
|
||||
(int)(context.length / stepLength) - 1);
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the count relationship between two contexts.
|
||||
*
|
||||
* EQUAL: Equal set of nodes and every count is equal.
|
||||
* GREATER_THAN: Superset of nodes and every count is equal or greater than its corollary.
|
||||
* LESS_THAN: Subset of nodes and every count is equal or less than its corollary.
|
||||
* DISJOINT: Node sets are not equal and/or counts are not all greater or less than.
|
||||
*
|
||||
* Strategy:
|
||||
* compare node logical clocks (like a version vector).
|
||||
*
|
||||
* @param left
|
||||
* counter context.
|
||||
* @param right
|
||||
* counter context.
|
||||
* @return the ContextRelationship between the contexts.
|
||||
*/
|
||||
public ContextRelationship diff(byte[] left, byte[] right)
|
||||
{
|
||||
left = sortElementsById(left);
|
||||
right = sortElementsById(right);
|
||||
|
||||
ContextRelationship relationship = ContextRelationship.EQUAL;
|
||||
|
||||
int leftIndex = 0;
|
||||
int rightIndex = 0;
|
||||
while (leftIndex < left.length && rightIndex < right.length)
|
||||
{
|
||||
// compare id bytes
|
||||
int compareId = FBUtilities.compareByteSubArrays(left, leftIndex, right, rightIndex, idLength);
|
||||
if (compareId == 0)
|
||||
{
|
||||
long leftClock = FBUtilities.byteArrayToLong(left, leftIndex + idLength);
|
||||
long rightClock = FBUtilities.byteArrayToLong(right, rightIndex + idLength);
|
||||
|
||||
// advance indexes
|
||||
leftIndex += stepLength;
|
||||
rightIndex += stepLength;
|
||||
|
||||
// process clock comparisons
|
||||
if (leftClock == rightClock)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (leftClock > rightClock)
|
||||
{
|
||||
if (relationship == ContextRelationship.EQUAL)
|
||||
{
|
||||
relationship = ContextRelationship.GREATER_THAN;
|
||||
}
|
||||
else if (relationship == ContextRelationship.GREATER_THAN)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// relationship == ContextRelationship.LESS_THAN
|
||||
return ContextRelationship.DISJOINT;
|
||||
}
|
||||
}
|
||||
else
|
||||
// leftClock < rightClock
|
||||
{
|
||||
if (relationship == ContextRelationship.EQUAL)
|
||||
{
|
||||
relationship = ContextRelationship.LESS_THAN;
|
||||
}
|
||||
else if (relationship == ContextRelationship.GREATER_THAN)
|
||||
{
|
||||
return ContextRelationship.DISJOINT;
|
||||
}
|
||||
else
|
||||
{
|
||||
// relationship == ContextRelationship.LESS_THAN
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (compareId > 0)
|
||||
{
|
||||
// only advance the right context
|
||||
rightIndex += stepLength;
|
||||
|
||||
if (relationship == ContextRelationship.EQUAL)
|
||||
{
|
||||
relationship = ContextRelationship.LESS_THAN;
|
||||
}
|
||||
else if (relationship == ContextRelationship.GREATER_THAN)
|
||||
{
|
||||
return ContextRelationship.DISJOINT;
|
||||
}
|
||||
else
|
||||
{
|
||||
// relationship == ContextRelationship.LESS_THAN
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// compareId < 0
|
||||
// only advance the left context
|
||||
leftIndex += stepLength;
|
||||
|
||||
if (relationship == ContextRelationship.EQUAL)
|
||||
{
|
||||
relationship = ContextRelationship.GREATER_THAN;
|
||||
}
|
||||
else if (relationship == ContextRelationship.GREATER_THAN)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
// relationship == ContextRelationship.LESS_THAN
|
||||
{
|
||||
return ContextRelationship.DISJOINT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check final lengths
|
||||
if (leftIndex < left.length)
|
||||
{
|
||||
if (relationship == ContextRelationship.EQUAL)
|
||||
{
|
||||
return ContextRelationship.GREATER_THAN;
|
||||
}
|
||||
else if (relationship == ContextRelationship.LESS_THAN)
|
||||
{
|
||||
return ContextRelationship.DISJOINT;
|
||||
}
|
||||
}
|
||||
else if (rightIndex < right.length)
|
||||
{
|
||||
if (relationship == ContextRelationship.EQUAL)
|
||||
{
|
||||
return ContextRelationship.LESS_THAN;
|
||||
}
|
||||
else if (relationship == ContextRelationship.GREATER_THAN)
|
||||
{
|
||||
return ContextRelationship.DISJOINT;
|
||||
}
|
||||
}
|
||||
|
||||
return relationship;
|
||||
}
|
||||
|
||||
private class CounterNode
|
||||
{
|
||||
public final long clock;
|
||||
public final long count;
|
||||
|
||||
public CounterNode(long clock, long count)
|
||||
{
|
||||
this.clock = clock;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public int compareClockTo(CounterNode o)
|
||||
{
|
||||
if (clock == o.clock)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (clock > o.clock)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
// clock < o.clock
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "(" + clock + "," + count + ")";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a context w/ an aggregated count for each node id.
|
||||
*
|
||||
* @param left
|
||||
* counter context.
|
||||
* @param right
|
||||
* counter context.
|
||||
*/
|
||||
public byte[] merge(byte[] left, byte[] right)
|
||||
{
|
||||
// strategy:
|
||||
// 1) map id -> (clock, count)
|
||||
// a) local id: sum clocks, counts
|
||||
// b) remote id: keep highest clock, count (reconcile)
|
||||
// 2) create a context from sorted array
|
||||
Map<FBUtilities.ByteArrayWrapper, CounterNode> contextsMap =
|
||||
new HashMap<FBUtilities.ByteArrayWrapper, CounterNode>();
|
||||
|
||||
// map left context: id -> (clock, count)
|
||||
for (int offset = 0; offset < left.length; offset += stepLength)
|
||||
{
|
||||
FBUtilities.ByteArrayWrapper id = new FBUtilities.ByteArrayWrapper(
|
||||
ArrayUtils.subarray(left, offset, offset + idLength));
|
||||
long clock = FBUtilities.byteArrayToLong(left, offset + idLength);
|
||||
long count = FBUtilities.byteArrayToLong(left, offset + idLength + clockLength);
|
||||
|
||||
contextsMap.put(id, new CounterNode(clock, count));
|
||||
}
|
||||
|
||||
// map right context: id -> (clock, count)
|
||||
for (int offset = 0; offset < right.length; offset += stepLength)
|
||||
{
|
||||
FBUtilities.ByteArrayWrapper id = new FBUtilities.ByteArrayWrapper(
|
||||
ArrayUtils.subarray(right, offset, offset + idLength));
|
||||
long clock = FBUtilities.byteArrayToLong(right, offset + idLength);
|
||||
long count = FBUtilities.byteArrayToLong(right, offset + idLength + clockLength);
|
||||
|
||||
if (!contextsMap.containsKey(id))
|
||||
{
|
||||
contextsMap.put(id, new CounterNode(clock, count));
|
||||
continue;
|
||||
}
|
||||
|
||||
CounterNode node = contextsMap.get(id);
|
||||
|
||||
// local id: sum clocks, counts
|
||||
if (this.idWrapper.equals(id))
|
||||
{
|
||||
contextsMap.put(id, new CounterNode(
|
||||
clock + node.clock,
|
||||
count + node.count));
|
||||
continue;
|
||||
}
|
||||
|
||||
// remote id: keep highest clock and its count
|
||||
if (node.clock < clock)
|
||||
{
|
||||
contextsMap.put(id, new CounterNode(clock, count));
|
||||
}
|
||||
}
|
||||
|
||||
// sort merged tuples
|
||||
List<Map.Entry<FBUtilities.ByteArrayWrapper, CounterNode>> contextsList =
|
||||
new ArrayList<Map.Entry<FBUtilities.ByteArrayWrapper, CounterNode>>(
|
||||
contextsMap.entrySet());
|
||||
Collections.sort(
|
||||
contextsList,
|
||||
new Comparator<Map.Entry<FBUtilities.ByteArrayWrapper, CounterNode>>()
|
||||
{
|
||||
public int compare(
|
||||
Map.Entry<FBUtilities.ByteArrayWrapper, CounterNode> e1,
|
||||
Map.Entry<FBUtilities.ByteArrayWrapper, CounterNode> e2)
|
||||
{
|
||||
// reversed
|
||||
return e2.getValue().compareClockTo(e1.getValue());
|
||||
}
|
||||
});
|
||||
|
||||
// create merged context
|
||||
int length = contextsList.size();
|
||||
byte[] merged = new byte[length * stepLength];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
Map.Entry<FBUtilities.ByteArrayWrapper, CounterNode> entry = contextsList.get(i);
|
||||
writeElementAtStepOffset(
|
||||
merged,
|
||||
i,
|
||||
entry.getKey().data,
|
||||
entry.getValue().clock,
|
||||
entry.getValue().count);
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Human-readable String from context.
|
||||
*
|
||||
* @param context
|
||||
* version context.
|
||||
* @return a human-readable String of the context.
|
||||
*/
|
||||
public String toString(byte[] context)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[");
|
||||
for (int offset = 0; offset < context.length; offset += stepLength)
|
||||
{
|
||||
if (offset > 0)
|
||||
{
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append("{");
|
||||
try
|
||||
{
|
||||
InetAddress address = InetAddress.getByAddress(
|
||||
ArrayUtils.subarray(context, offset, offset + idLength));
|
||||
sb.append(address.getHostAddress());
|
||||
}
|
||||
catch (UnknownHostException uhe)
|
||||
{
|
||||
sb.append("?.?.?.?");
|
||||
}
|
||||
sb.append(", ");
|
||||
sb.append(FBUtilities.byteArrayToLong(context, offset + idLength));
|
||||
sb.append(", ");
|
||||
sb.append(FBUtilities.byteArrayToLong(context, offset + idLength + clockLength));
|
||||
|
||||
sb.append("}");
|
||||
}
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// return an aggregated count across all node ids
|
||||
public byte[] total(byte[] context)
|
||||
{
|
||||
long total = 0L;
|
||||
|
||||
for (int offset = 0; offset < context.length; offset += stepLength)
|
||||
{
|
||||
long count = FBUtilities.byteArrayToLong(context, offset + idLength + clockLength);
|
||||
total += count;
|
||||
}
|
||||
|
||||
return FBUtilities.toByteArray(total);
|
||||
}
|
||||
|
||||
// remove the count for a given node id
|
||||
public byte[] cleanNodeCounts(byte[] context, InetAddress node)
|
||||
{
|
||||
// calculate node id
|
||||
byte[] nodeId = node.getAddress();
|
||||
|
||||
// look for this node id
|
||||
for (int offset = 0; offset < context.length; offset += stepLength)
|
||||
{
|
||||
if (FBUtilities.compareByteSubArrays(context, offset, nodeId, 0, idLength) != 0)
|
||||
continue;
|
||||
|
||||
// node id found: remove node count
|
||||
byte[] truncatedContext = new byte[context.length - stepLength];
|
||||
System.arraycopy(context, 0, truncatedContext, 0, offset);
|
||||
System.arraycopy(
|
||||
context,
|
||||
offset + stepLength,
|
||||
truncatedContext,
|
||||
offset,
|
||||
context.length - (offset + stepLength));
|
||||
return truncatedContext;
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
package org.apache.cassandra.db.context;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An opaque commutative context.
|
||||
*
|
||||
* Maintains a byte[] context that represents a partitioned commutative value.
|
||||
*/
|
||||
public interface IContext
|
||||
{
|
||||
public static enum ContextRelationship
|
||||
{
|
||||
EQUAL,
|
||||
GREATER_THAN,
|
||||
LESS_THAN,
|
||||
DISJOINT
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an initial context.
|
||||
*
|
||||
* @return the initial context.
|
||||
*/
|
||||
public byte[] create();
|
||||
|
||||
/**
|
||||
* Determine the relationship between two contexts.
|
||||
*
|
||||
* EQUAL: Equal set of nodes and every count is equal.
|
||||
* GREATER_THAN: Superset of nodes and every count is equal or greater than its corollary.
|
||||
* LESS_THAN: Subset of nodes and every count is equal or less than its corollary.
|
||||
* DISJOINT: Node sets are not equal and/or counts are not all greater or less than.
|
||||
*
|
||||
* @param left
|
||||
* context.
|
||||
* @param right
|
||||
* context.
|
||||
* @return the ContextRelationship between the contexts.
|
||||
*/
|
||||
public ContextRelationship diff(byte[] left, byte[] right);
|
||||
|
||||
/**
|
||||
* Return a context w/ an aggregated count for each node id.
|
||||
*
|
||||
* @param left
|
||||
* context.
|
||||
* @param right
|
||||
* context.
|
||||
*/
|
||||
public byte[] merge(byte[] left, byte[] right);
|
||||
|
||||
/**
|
||||
* Human-readable String from context.
|
||||
*
|
||||
* @param context
|
||||
* context.
|
||||
* @return a human-readable String of the context.
|
||||
*/
|
||||
public String toString(byte[] context);
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
package org.apache.cassandra.db.marshal;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.cassandra.db.Column;
|
||||
import org.apache.cassandra.db.IColumnContainer;
|
||||
|
||||
public abstract class AbstractCommutativeType extends AbstractType
|
||||
{
|
||||
public boolean isCommutative()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* create commutative column
|
||||
*/
|
||||
public abstract Column createColumn(ByteBuffer name, ByteBuffer value, long timestamp);
|
||||
|
||||
/**
|
||||
* update commutative columns for target node
|
||||
*/
|
||||
public abstract void update(IColumnContainer cc, InetAddress node);
|
||||
|
||||
/**
|
||||
* remove target node from commutative columns
|
||||
*/
|
||||
public abstract void cleanContext(IColumnContainer cc, InetAddress node);
|
||||
}
|
||||
|
|
@ -91,4 +91,9 @@ public abstract class AbstractType implements Comparator<ByteBuffer>
|
|||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public boolean isCommutative()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
package org.apache.cassandra.db.marshal;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.cassandra.db.ColumnFamily;
|
||||
import org.apache.cassandra.db.CounterColumn;
|
||||
import org.apache.cassandra.db.Column;
|
||||
import org.apache.cassandra.db.DeletedColumn;
|
||||
import org.apache.cassandra.db.IColumn;
|
||||
import org.apache.cassandra.db.IColumnContainer;
|
||||
import org.apache.cassandra.db.SuperColumn;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
||||
public class CounterColumnType extends AbstractCommutativeType
|
||||
{
|
||||
public static final CounterColumnType instance = new CounterColumnType();
|
||||
|
||||
CounterColumnType() {} // singleton
|
||||
|
||||
public int compare(ByteBuffer o1, ByteBuffer o2)
|
||||
{
|
||||
if (o1.remaining() == 0)
|
||||
{
|
||||
return o2.remaining() == 0 ? 0 : -1;
|
||||
}
|
||||
if (o2.remaining() == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return ByteBufferUtil.compareUnsigned(o1, o2);
|
||||
}
|
||||
|
||||
public String getString(ByteBuffer bytes)
|
||||
{
|
||||
if (bytes.remaining() == 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
if (bytes.remaining() != 8)
|
||||
{
|
||||
throw new MarshalException("A long is exactly 8 bytes");
|
||||
}
|
||||
return String.valueOf(bytes.getLong(bytes.position()+bytes.arrayOffset()));
|
||||
}
|
||||
|
||||
/**
|
||||
* create commutative column
|
||||
*/
|
||||
public Column createColumn(ByteBuffer name, ByteBuffer value, long timestamp)
|
||||
{
|
||||
return new CounterColumn(name, value, timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* update commutative columns for target node
|
||||
*/
|
||||
public void update(IColumnContainer cc, InetAddress node)
|
||||
{
|
||||
for (IColumn column : cc.getSortedColumns())
|
||||
{
|
||||
if (column instanceof SuperColumn)
|
||||
{
|
||||
update((IColumnContainer)column, node);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (column instanceof DeletedColumn)
|
||||
continue;
|
||||
|
||||
((CounterColumn)column).update(node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* remove target node from commutative columns
|
||||
*/
|
||||
public void cleanContext(IColumnContainer cc, InetAddress node)
|
||||
{
|
||||
if ((cc instanceof ColumnFamily) && ((ColumnFamily)cc).isSuper())
|
||||
{
|
||||
for (IColumn column : cc.getSortedColumns())
|
||||
{
|
||||
SuperColumn supercol = (SuperColumn)column;
|
||||
cleanContext(supercol, node);
|
||||
if (0 == supercol.getSubColumns().size())
|
||||
cc.remove(supercol.name());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (IColumn column : cc.getSortedColumns())
|
||||
{
|
||||
CounterColumn counterColumn = (CounterColumn)column;
|
||||
CounterColumn cleanedColumn = counterColumn.cleanNodeCounts(node);
|
||||
if (cleanedColumn == counterColumn)
|
||||
continue;
|
||||
cc.remove(counterColumn.name());
|
||||
//XXX: on "clean," must copy-and-replace
|
||||
if (null != cleanedColumn)
|
||||
cc.addColumn(cleanedColumn);
|
||||
}
|
||||
}
|
||||
|
||||
public void validate(ByteBuffer bytes) throws MarshalException
|
||||
{
|
||||
if (bytes.remaining() != 8 && bytes.remaining() != 0)
|
||||
throw new MarshalException(String.format("Expected 8 or 0 byte long (%d)", bytes.remaining()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -45,6 +45,7 @@ package org.apache.cassandra.dht;
|
|||
import org.apache.cassandra.net.Message;
|
||||
import org.apache.cassandra.net.MessagingService;
|
||||
import org.apache.cassandra.service.StorageService;
|
||||
import org.apache.cassandra.streaming.OperationType;
|
||||
import org.apache.cassandra.streaming.StreamIn;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.SimpleCondition;
|
||||
|
|
@ -107,8 +108,8 @@ public class BootStrapper
|
|||
}
|
||||
};
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Bootstrapping from " + source + " ranges " + StringUtils.join(ranges, ", "));
|
||||
StreamIn.requestRanges(source, table, ranges, callback);
|
||||
logger.debug("Bootstrapping from " + source + " ranges " + StringUtils.join(entry.getValue(), ", "));
|
||||
StreamIn.requestRanges(source, table, entry.getValue(), callback, OperationType.BOOTSTRAP);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
package org.apache.cassandra.io.sstable;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.InetAddress;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
|
|
@ -31,6 +33,9 @@ import java.util.Set;
|
|||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.db.*;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.AbstractCommutativeType;
|
||||
import org.apache.cassandra.db.ColumnFamily;
|
||||
import org.apache.cassandra.db.ColumnFamilyStore;
|
||||
import org.apache.cassandra.db.DecoratedKey;
|
||||
|
|
@ -43,6 +48,7 @@ import org.apache.cassandra.io.util.FileMark;
|
|||
import org.apache.cassandra.io.util.FileUtils;
|
||||
import org.apache.cassandra.io.util.SegmentedFile;
|
||||
import org.apache.cassandra.service.StorageService;
|
||||
import org.apache.cassandra.streaming.OperationType;
|
||||
import org.apache.cassandra.utils.BloomFilter;
|
||||
import org.apache.cassandra.utils.EstimatedHistogram;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
|
@ -221,7 +227,7 @@ public class SSTableWriter extends SSTable
|
|||
return dataFile.getFilePointer();
|
||||
}
|
||||
|
||||
public static Builder createBuilder(Descriptor desc)
|
||||
public static Builder createBuilder(Descriptor desc, OperationType type)
|
||||
{
|
||||
if (!desc.isLatestVersion)
|
||||
// TODO: streaming between different versions will fail: need support for
|
||||
|
|
@ -229,7 +235,7 @@ public class SSTableWriter extends SSTable
|
|||
throw new RuntimeException(String.format("Cannot recover SSTable with version %s (current version %s).",
|
||||
desc.version, Descriptor.CURRENT_VERSION));
|
||||
|
||||
return new Builder(desc);
|
||||
return new Builder(desc, type);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -240,16 +246,18 @@ public class SSTableWriter extends SSTable
|
|||
{
|
||||
private final Descriptor desc;
|
||||
public final ColumnFamilyStore cfs;
|
||||
private BufferedRandomAccessFile dfile;
|
||||
private final RowIndexer indexer;
|
||||
|
||||
public Builder(Descriptor desc)
|
||||
public Builder(Descriptor desc, OperationType type)
|
||||
{
|
||||
|
||||
this.desc = desc;
|
||||
cfs = Table.open(desc.ksname).getColumnFamilyStore(desc.cfname);
|
||||
try
|
||||
{
|
||||
dfile = new BufferedRandomAccessFile(desc.filenameFor(SSTable.COMPONENT_DATA), "r", 8 * 1024 * 1024);
|
||||
if (OperationType.AES == type && cfs.metadata.getDefaultValidator().isCommutative())
|
||||
indexer = new AESCommutativeRowIndexer(desc, cfs.metadata);
|
||||
else
|
||||
indexer = new RowIndexer(desc, cfs.metadata);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
|
|
@ -266,47 +274,79 @@ public class SSTableWriter extends SSTable
|
|||
assert !ifile.exists();
|
||||
assert !ffile.exists();
|
||||
|
||||
EstimatedHistogram rowSizes = SSTable.defaultRowHistogram();
|
||||
EstimatedHistogram columnCounts = SSTable.defaultColumnHistogram();
|
||||
long estimatedRows = indexer.prepareIndexing();
|
||||
|
||||
IndexWriter iwriter;
|
||||
// build the index and filter
|
||||
long rows = indexer.index();
|
||||
|
||||
logger.debug("estimated row count was {} of real count", ((double)estimatedRows) / rows);
|
||||
return SSTableReader.open(rename(desc, SSTable.componentsFor(desc)));
|
||||
}
|
||||
|
||||
public long getTotalBytes()
|
||||
{
|
||||
try
|
||||
{
|
||||
return indexer.dfile.length();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new IOError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public long getBytesRead()
|
||||
{
|
||||
return indexer.dfile.getFilePointer();
|
||||
}
|
||||
|
||||
public String getTaskType()
|
||||
{
|
||||
return "SSTable rebuild";
|
||||
}
|
||||
}
|
||||
|
||||
static class RowIndexer
|
||||
{
|
||||
protected final Descriptor desc;
|
||||
public final BufferedRandomAccessFile dfile;
|
||||
|
||||
protected IndexWriter iwriter;
|
||||
protected CFMetaData metadata;
|
||||
|
||||
RowIndexer(Descriptor desc, CFMetaData metadata) throws IOException
|
||||
{
|
||||
this(desc, new BufferedRandomAccessFile(desc.filenameFor(SSTable.COMPONENT_DATA), "r", 8 * 1024 * 1024), metadata);
|
||||
}
|
||||
|
||||
protected RowIndexer(Descriptor desc, BufferedRandomAccessFile dfile, CFMetaData metadata) throws IOException
|
||||
{
|
||||
this.desc = desc;
|
||||
this.dfile = dfile;
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
long prepareIndexing() throws IOException
|
||||
{
|
||||
long estimatedRows;
|
||||
try
|
||||
{
|
||||
estimatedRows = SSTable.estimateRowsFromData(desc, dfile);
|
||||
iwriter = new IndexWriter(desc, StorageService.getPartitioner(), estimatedRows);
|
||||
return estimatedRows;
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
dfile.close();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// build the index and filter
|
||||
long rows = 0;
|
||||
long index() throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
DecoratedKey key;
|
||||
long rowPosition = 0;
|
||||
while (rowPosition < dfile.length())
|
||||
{
|
||||
key = SSTableReader.decodeKey(StorageService.getPartitioner(), desc, FBUtilities.readShortByteArray(dfile));
|
||||
iwriter.afterAppend(key, rowPosition);
|
||||
|
||||
long dataSize = SSTableReader.readRowSize(dfile, desc);
|
||||
rowPosition = dfile.getFilePointer() + dataSize; // next row
|
||||
|
||||
IndexHelper.skipBloomFilter(dfile);
|
||||
IndexHelper.skipIndex(dfile);
|
||||
ColumnFamily.serializer().deserializeFromSSTableNoColumns(ColumnFamily.create(cfs.metadata), dfile);
|
||||
rowSizes.add(dataSize);
|
||||
columnCounts.add(dfile.readInt());
|
||||
|
||||
dfile.seek(rowPosition);
|
||||
rows++;
|
||||
}
|
||||
|
||||
writeStatistics(desc, rowSizes, columnCounts);
|
||||
return doIndexing();
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
@ -320,31 +360,113 @@ public class SSTableWriter extends SSTable
|
|||
throw new IOError(e);
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug("estimated row count was %s of real count", ((double)estimatedRows) / rows);
|
||||
return SSTableReader.open(rename(desc, SSTable.componentsFor(desc)));
|
||||
}
|
||||
|
||||
public long getTotalBytes()
|
||||
protected long doIndexing() throws IOException
|
||||
{
|
||||
try
|
||||
EstimatedHistogram rowSizes = SSTable.defaultRowHistogram();
|
||||
EstimatedHistogram columnCounts = SSTable.defaultColumnHistogram();
|
||||
long rows = 0;
|
||||
DecoratedKey key;
|
||||
long rowPosition = 0;
|
||||
while (rowPosition < dfile.length())
|
||||
{
|
||||
return dfile.length();
|
||||
// read key
|
||||
key = SSTableReader.decodeKey(StorageService.getPartitioner(), desc, FBUtilities.readShortByteArray(dfile));
|
||||
iwriter.afterAppend(key, rowPosition);
|
||||
|
||||
// seek to next key
|
||||
long dataSize = SSTableReader.readRowSize(dfile, desc);
|
||||
rowPosition = dfile.getFilePointer() + dataSize;
|
||||
|
||||
IndexHelper.skipBloomFilter(dfile);
|
||||
IndexHelper.skipIndex(dfile);
|
||||
ColumnFamily.serializer().deserializeFromSSTableNoColumns(ColumnFamily.create(metadata), dfile);
|
||||
rowSizes.add(dataSize);
|
||||
columnCounts.add(dfile.readInt());
|
||||
|
||||
dfile.seek(rowPosition);
|
||||
|
||||
rows++;
|
||||
}
|
||||
catch (IOException e)
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
|
||||
static class AESCommutativeRowIndexer extends RowIndexer
|
||||
{
|
||||
AESCommutativeRowIndexer(Descriptor desc, CFMetaData metadata) throws IOException
|
||||
{
|
||||
super(desc, new BufferedRandomAccessFile(desc.filenameFor(SSTable.COMPONENT_DATA), "rw", 8 * 1024 * 1024), metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long doIndexing() throws IOException
|
||||
{
|
||||
EstimatedHistogram rowSizes = SSTable.defaultRowHistogram();
|
||||
EstimatedHistogram columnCounts = SSTable.defaultColumnHistogram();
|
||||
long rows = 0L;
|
||||
ByteBuffer diskKey;
|
||||
DecoratedKey key;
|
||||
|
||||
long readRowPosition = 0L;
|
||||
long writeRowPosition = 0L;
|
||||
while (readRowPosition < dfile.length())
|
||||
{
|
||||
throw new IOError(e);
|
||||
// read key
|
||||
dfile.seek(readRowPosition);
|
||||
diskKey = FBUtilities.readShortByteArray(dfile);
|
||||
|
||||
// skip data size, bloom filter, column index
|
||||
long dataSize = SSTableReader.readRowSize(dfile, desc);
|
||||
dfile.skipBytes(dfile.readInt());
|
||||
dfile.skipBytes(dfile.readInt());
|
||||
|
||||
// deserialize CF
|
||||
ColumnFamily cf = ColumnFamily.create(desc.ksname, desc.cfname);
|
||||
ColumnFamily.serializer().deserializeFromSSTableNoColumns(cf, dfile);
|
||||
ColumnFamily.serializer().deserializeColumns(dfile, cf);
|
||||
rowSizes.add(dataSize);
|
||||
columnCounts.add(cf.getEstimatedColumnCount());
|
||||
|
||||
// remove source node from CF's commutative columns
|
||||
((AbstractCommutativeType)cf.metadata().getDefaultValidator()).cleanContext(cf, FBUtilities.getLocalAddress());
|
||||
|
||||
readRowPosition = dfile.getFilePointer();
|
||||
|
||||
|
||||
// update index writer
|
||||
key = SSTableReader.decodeKey(StorageService.getPartitioner(), desc, diskKey);
|
||||
iwriter.afterAppend(key, writeRowPosition);
|
||||
|
||||
|
||||
// write key
|
||||
dfile.seek(writeRowPosition);
|
||||
FBUtilities.writeShortByteArray(diskKey, dfile);
|
||||
|
||||
// write data size; serialize CF w/ bloom filter, column index
|
||||
long writeSizePosition = dfile.getFilePointer();
|
||||
dfile.writeLong(-1L);
|
||||
ColumnFamily.serializer().serializeWithIndexes(cf, dfile);
|
||||
long writeEndPosition = dfile.getFilePointer();
|
||||
dfile.seek(writeSizePosition);
|
||||
dfile.writeLong(writeEndPosition - (writeSizePosition + 8L));
|
||||
|
||||
writeRowPosition = writeEndPosition;
|
||||
|
||||
rows++;
|
||||
|
||||
dfile.sync();
|
||||
}
|
||||
}
|
||||
|
||||
public long getBytesRead()
|
||||
{
|
||||
return dfile.getFilePointer();
|
||||
}
|
||||
if (writeRowPosition != readRowPosition)
|
||||
{
|
||||
// truncate file to new, reduced length
|
||||
dfile.setLength(writeRowPosition);
|
||||
dfile.sync();
|
||||
}
|
||||
|
||||
public String getTaskType()
|
||||
{
|
||||
return "SSTable rebuild";
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ import org.apache.cassandra.dht.Token;
|
|||
import org.apache.cassandra.io.AbstractCompactedRow;
|
||||
import org.apache.cassandra.io.ICompactSerializer;
|
||||
import org.apache.cassandra.io.sstable.SSTableReader;
|
||||
import org.apache.cassandra.streaming.OperationType;
|
||||
import org.apache.cassandra.streaming.StreamIn;
|
||||
import org.apache.cassandra.streaming.StreamOut;
|
||||
import org.apache.cassandra.net.CompactEndpointSerializationHelper;
|
||||
|
|
@ -502,9 +503,9 @@ public class AntiEntropyService
|
|||
Callback callback = new Callback();
|
||||
// send ranges to the remote node
|
||||
StreamOutSession outsession = StreamOutSession.create(request.cf.left, request.endpoint, callback);
|
||||
StreamOut.transferSSTables(outsession, sstables, ranges);
|
||||
StreamOut.transferSSTables(outsession, sstables, ranges, OperationType.AES);
|
||||
// request ranges from the remote node
|
||||
StreamIn.requestRanges(request.endpoint, request.cf.left, ranges, callback);
|
||||
StreamIn.requestRanges(request.endpoint, request.cf.left, ranges, callback, OperationType.AES);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ import java.io.IOException;
|
|||
import java.util.*;
|
||||
|
||||
import org.apache.cassandra.db.*;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.AbstractCommutativeType;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
|
@ -52,6 +54,13 @@ public class ReadResponseResolver implements IResponseResolver<Row>
|
|||
this.table = table;
|
||||
this.key = StorageService.getPartitioner().decorateKey(key);
|
||||
}
|
||||
|
||||
private void checkDigest(DecoratedKey key, ByteBuffer digest, ByteBuffer resultDigest) throws DigestMismatchException
|
||||
{
|
||||
if (resultDigest.equals(digest))
|
||||
return;
|
||||
throw new DigestMismatchException(key, digest, resultDigest);
|
||||
}
|
||||
|
||||
/*
|
||||
* This method for resolving read data should look at the timestamps of each
|
||||
|
|
@ -82,21 +91,25 @@ public class ReadResponseResolver implements IResponseResolver<Row>
|
|||
Message message = entry.getKey();
|
||||
if (result.isDigestQuery())
|
||||
{
|
||||
if (digest == null)
|
||||
{
|
||||
digest = result.digest();
|
||||
}
|
||||
else
|
||||
{
|
||||
ByteBuffer digest2 = result.digest();
|
||||
if (!digest.equals(digest2))
|
||||
throw new DigestMismatchException(key, digest, digest2);
|
||||
}
|
||||
if (digest != null)
|
||||
checkDigest(key, digest, result.digest());
|
||||
digest = result.digest();
|
||||
}
|
||||
else
|
||||
{
|
||||
versions.add(result.row().cf);
|
||||
endpoints.add(message.getFrom());
|
||||
ColumnFamily cf = result.row().cf;
|
||||
InetAddress from = message.getFrom();
|
||||
|
||||
if(cf != null) {
|
||||
AbstractType defaultValidator = cf.metadata().getDefaultValidator();
|
||||
if (!FBUtilities.getLocalAddress().equals(from) && cf != null && defaultValidator.isCommutative())
|
||||
{
|
||||
cf = cf.cloneMe();
|
||||
((AbstractCommutativeType)defaultValidator).cleanContext(cf, FBUtilities.getLocalAddress());
|
||||
}
|
||||
}
|
||||
versions.add(cf);
|
||||
endpoints.add(from);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -107,9 +120,7 @@ public class ReadResponseResolver implements IResponseResolver<Row>
|
|||
|
||||
for (ColumnFamily cf : versions)
|
||||
{
|
||||
ByteBuffer digest2 = ColumnFamily.digest(cf);
|
||||
if (!digest.equals(digest2))
|
||||
throw new DigestMismatchException(key, digest, digest2);
|
||||
checkDigest(key, digest, ColumnFamily.digest(cf));
|
||||
}
|
||||
if (logger_.isDebugEnabled())
|
||||
logger_.debug("digests verified");
|
||||
|
|
@ -147,6 +158,14 @@ public class ReadResponseResolver implements IResponseResolver<Row>
|
|||
|
||||
// create and send the row mutation message based on the diff
|
||||
RowMutation rowMutation = new RowMutation(table, key.key);
|
||||
|
||||
AbstractType defaultValidator = diffCf.metadata().getDefaultValidator();
|
||||
if (defaultValidator.isCommutative())
|
||||
((AbstractCommutativeType)defaultValidator).cleanContext(diffCf, endpoints.get(i));
|
||||
|
||||
if (diffCf.getColumnsMap().isEmpty() && !diffCf.isMarkedForDelete())
|
||||
continue;
|
||||
|
||||
rowMutation.add(diffCf);
|
||||
RowMutationMessage rowMutationMessage = new RowMutationMessage(rowMutation);
|
||||
Message repairMessage;
|
||||
|
|
@ -170,7 +189,7 @@ public class ReadResponseResolver implements IResponseResolver<Row>
|
|||
{
|
||||
if (cf != null)
|
||||
{
|
||||
resolved = cf.cloneMe();
|
||||
resolved = cf.cloneMeShallow();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ import org.apache.cassandra.concurrent.StageManager;
|
|||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.db.*;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.AbstractCommutativeType;
|
||||
import org.apache.cassandra.dht.*;
|
||||
import org.apache.cassandra.gms.Gossiper;
|
||||
import org.apache.cassandra.locator.AbstractReplicationStrategy;
|
||||
|
|
@ -117,6 +119,10 @@ public class StorageProxy implements StorageProxyMBean
|
|||
|
||||
responseHandlers.add(responseHandler);
|
||||
Message unhintedMessage = null;
|
||||
|
||||
//XXX: if commutative value, only allow CL.ONE write
|
||||
updateDestinationForCommutativeTypes(consistency_level, rm, hintedEndpoints);
|
||||
|
||||
for (Map.Entry<InetAddress, Collection<InetAddress>> entry : hintedEndpoints.asMap().entrySet())
|
||||
{
|
||||
InetAddress destination = entry.getKey();
|
||||
|
|
@ -124,6 +130,9 @@ public class StorageProxy implements StorageProxyMBean
|
|||
|
||||
if (targets.size() == 1 && targets.iterator().next().equals(destination))
|
||||
{
|
||||
// only non-hinted writes are supported
|
||||
rm.updateCommutativeTypes(destination);
|
||||
|
||||
// unhinted writes
|
||||
if (destination.equals(FBUtilities.getLocalAddress()))
|
||||
{
|
||||
|
|
@ -180,6 +189,40 @@ public class StorageProxy implements StorageProxyMBean
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Update destination endpoints depending on the clock type.
|
||||
*/
|
||||
private static void updateDestinationForCommutativeTypes(ConsistencyLevel consistency_level, RowMutation rm,
|
||||
Multimap<InetAddress, InetAddress> destinationEndpoints)
|
||||
{
|
||||
AbstractType defaultValidator = rm.getColumnFamilies().iterator().next().metadata().getDefaultValidator();
|
||||
if (!defaultValidator.isCommutative())
|
||||
return;
|
||||
|
||||
InetAddress randomDestination = pickRandomDestination(destinationEndpoints);
|
||||
destinationEndpoints.clear();
|
||||
destinationEndpoints.put(randomDestination, randomDestination);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param endpoints potential destinations.
|
||||
* @return one destination randomly chosen from the endpoints unless localhost is in the map, then that is returned.
|
||||
*/
|
||||
private static InetAddress pickRandomDestination(Multimap<InetAddress, InetAddress> endpoints)
|
||||
{
|
||||
Set<InetAddress> destinationSet = endpoints.keySet();
|
||||
|
||||
if (destinationSet.contains(FBUtilities.getLocalAddress()))
|
||||
{
|
||||
return FBUtilities.getLocalAddress();
|
||||
}
|
||||
else
|
||||
{
|
||||
InetAddress[] destinations = destinationSet.toArray(new InetAddress[0]);
|
||||
return destinations[random.nextInt(destinations.length)];
|
||||
}
|
||||
}
|
||||
|
||||
private static void addHintHeader(Message message, InetAddress target) throws IOException
|
||||
{
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
|
|
@ -203,6 +246,10 @@ public class StorageProxy implements StorageProxyMBean
|
|||
{
|
||||
rm.deepCopy().apply();
|
||||
responseHandler.response(null);
|
||||
|
||||
// repair-on-write (local message)
|
||||
ReplicateOnWriteTask replicateOnWriteTask = new ReplicateOnWriteTask(rm);
|
||||
StageManager.getStage(Stage.REPLICATE_ON_WRITE).execute(replicateOnWriteTask);
|
||||
}
|
||||
};
|
||||
StageManager.getStage(Stage.MUTATION).execute(runnable);
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ import org.apache.cassandra.db.HintedHandOffManager;
|
|||
import org.apache.cassandra.db.ReadCommand;
|
||||
import org.apache.cassandra.db.ReadRepairVerbHandler;
|
||||
import org.apache.cassandra.db.ReadVerbHandler;
|
||||
import org.apache.cassandra.db.ReplicateOnWriteVerbHandler;
|
||||
import org.apache.cassandra.db.Row;
|
||||
import org.apache.cassandra.db.RowMutationVerbHandler;
|
||||
import org.apache.cassandra.db.SchemaCheckVerbHandler;
|
||||
|
|
@ -101,6 +102,7 @@ import org.apache.cassandra.net.Message;
|
|||
import org.apache.cassandra.net.MessagingService;
|
||||
import org.apache.cassandra.net.ResponseVerbHandler;
|
||||
import org.apache.cassandra.service.AntiEntropyService.TreeRequestVerbHandler;
|
||||
import org.apache.cassandra.streaming.OperationType;
|
||||
import org.apache.cassandra.streaming.ReplicationFinishedVerbHandler;
|
||||
import org.apache.cassandra.streaming.StreamIn;
|
||||
import org.apache.cassandra.streaming.StreamOut;
|
||||
|
|
@ -165,6 +167,7 @@ public class StorageService implements IEndpointStateChangeSubscriber, StorageSe
|
|||
INDEX_SCAN,
|
||||
REPLICATION_FINISHED,
|
||||
INTERNAL_RESPONSE, // responses to internal calls
|
||||
REPLICATE_ON_WRITE,
|
||||
;
|
||||
// remember to add new verbs at the end, since we serialize by ordinal
|
||||
}
|
||||
|
|
@ -193,6 +196,7 @@ public class StorageService implements IEndpointStateChangeSubscriber, StorageSe
|
|||
put(Verb.INDEX_SCAN, Stage.READ);
|
||||
put(Verb.REPLICATION_FINISHED, Stage.MISC);
|
||||
put(Verb.INTERNAL_RESPONSE, Stage.INTERNAL_RESPONSE);
|
||||
put(Verb.REPLICATE_ON_WRITE, Stage.REPLICATE_ON_WRITE);
|
||||
}};
|
||||
|
||||
|
||||
|
|
@ -278,6 +282,7 @@ public class StorageService implements IEndpointStateChangeSubscriber, StorageSe
|
|||
MessagingService.instance.registerVerbHandlers(Verb.MUTATION, new RowMutationVerbHandler());
|
||||
MessagingService.instance.registerVerbHandlers(Verb.READ_REPAIR, new ReadRepairVerbHandler());
|
||||
MessagingService.instance.registerVerbHandlers(Verb.READ, new ReadVerbHandler());
|
||||
MessagingService.instance.registerVerbHandlers(Verb.REPLICATE_ON_WRITE, new ReplicateOnWriteVerbHandler());
|
||||
MessagingService.instance.registerVerbHandlers(Verb.RANGE_SLICE, new RangeSliceVerbHandler());
|
||||
MessagingService.instance.registerVerbHandlers(Verb.INDEX_SCAN, new IndexScanVerbHandler());
|
||||
// see BootStrapper for a summary of how the bootstrap verbs interact
|
||||
|
|
@ -1004,7 +1009,7 @@ public class StorageService implements IEndpointStateChangeSubscriber, StorageSe
|
|||
};
|
||||
if (logger_.isDebugEnabled())
|
||||
logger_.debug("Requesting from " + source + " ranges " + StringUtils.join(ranges, ", "));
|
||||
StreamIn.requestRanges(source, table, ranges, callback);
|
||||
StreamIn.requestRanges(source, table, ranges, callback, OperationType.RESTORE_REPLICA_COUNT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1608,7 +1613,7 @@ public class StorageService implements IEndpointStateChangeSubscriber, StorageSe
|
|||
public void run()
|
||||
{
|
||||
// TODO each call to transferRanges re-flushes, this is potentially a lot of waste
|
||||
StreamOut.transferRanges(newEndpoint, table, Arrays.asList(range), callback);
|
||||
StreamOut.transferRanges(newEndpoint, table, Arrays.asList(range), callback, OperationType.UNBOOTSTRAP);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -1979,6 +1984,7 @@ public class StorageService implements IEndpointStateChangeSubscriber, StorageSe
|
|||
rcf.comment = cfm.getComment();
|
||||
rcf.keys_cached = cfm.getKeyCacheSize();
|
||||
rcf.read_repair_chance = cfm.getReadRepairChance();
|
||||
rcf.replicate_on_write = cfm.getReplicateOnWrite();
|
||||
rcf.gc_grace_seconds = cfm.getGcGraceSeconds();
|
||||
rcf.rows_cached = cfm.getRowCacheSize();
|
||||
rcf.column_metadata = new RawColumnDefinition[cfm.getColumn_metadata().size()];
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.apache.cassandra.streaming;
|
||||
|
||||
/**
|
||||
* Streaming operation type.
|
||||
*/
|
||||
public enum OperationType
|
||||
{
|
||||
AES,
|
||||
BOOTSTRAP,
|
||||
UNBOOTSTRAP,
|
||||
RESTORE_REPLICA_COUNT;
|
||||
}
|
||||
|
||||
|
|
@ -52,20 +52,23 @@ public class PendingFile
|
|||
public final Descriptor desc;
|
||||
public final String component;
|
||||
public final List<Pair<Long,Long>> sections;
|
||||
public final OperationType type;
|
||||
public final long size;
|
||||
public long progress;
|
||||
|
||||
public PendingFile(Descriptor desc, PendingFile pf)
|
||||
{
|
||||
this(null, desc, pf.component, pf.sections);
|
||||
this(null, desc, pf.component, pf.sections, pf.type);
|
||||
}
|
||||
|
||||
public PendingFile(SSTable sstable, Descriptor desc, String component, List<Pair<Long,Long>> sections)
|
||||
public PendingFile(SSTable sstable, Descriptor desc, String component, List<Pair<Long,Long>> sections, OperationType type)
|
||||
{
|
||||
this.sstable = sstable;
|
||||
this.desc = desc;
|
||||
this.component = component;
|
||||
this.sections = sections;
|
||||
this.type = type;
|
||||
|
||||
long tempSize = 0;
|
||||
for(Pair<Long,Long> section : sections)
|
||||
{
|
||||
|
|
@ -115,6 +118,7 @@ public class PendingFile
|
|||
{
|
||||
dos.writeLong(section.left); dos.writeLong(section.right);
|
||||
}
|
||||
dos.writeUTF(sc.type.name());
|
||||
}
|
||||
|
||||
public PendingFile deserialize(DataInputStream dis) throws IOException
|
||||
|
|
@ -129,7 +133,8 @@ public class PendingFile
|
|||
List<Pair<Long,Long>> sections = new ArrayList<Pair<Long,Long>>(count);
|
||||
for (int i = 0; i < count; i++)
|
||||
sections.add(new Pair<Long,Long>(Long.valueOf(dis.readLong()), Long.valueOf(dis.readLong())));
|
||||
return new PendingFile(null, desc, component, sections);
|
||||
OperationType type = OperationType.valueOf(dis.readUTF());
|
||||
return new PendingFile(null, desc, component, sections, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,19 +49,19 @@ public class StreamIn
|
|||
/**
|
||||
* Request ranges to be transferred from source to local node
|
||||
*/
|
||||
public static void requestRanges(InetAddress source, String tableName, Collection<Range> ranges)
|
||||
public static void requestRanges(InetAddress source, String tableName, Collection<Range> ranges, OperationType type)
|
||||
{
|
||||
requestRanges(source, tableName, ranges, null);
|
||||
requestRanges(source, tableName, ranges, null, type);
|
||||
}
|
||||
|
||||
public static void requestRanges(InetAddress source, String tableName, Collection<Range> ranges, Runnable callback)
|
||||
public static void requestRanges(InetAddress source, String tableName, Collection<Range> ranges, Runnable callback, OperationType type)
|
||||
{
|
||||
assert ranges.size() > 0;
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Requesting from {} ranges {}", source, StringUtils.join(ranges, ", "));
|
||||
StreamInSession session = StreamInSession.create(source, callback);
|
||||
Message message = new StreamRequestMessage(FBUtilities.getLocalAddress(), ranges, tableName, session.getSessionId()).makeMessage();
|
||||
Message message = new StreamRequestMessage(FBUtilities.getLocalAddress(), ranges, tableName, session.getSessionId(), type).makeMessage();
|
||||
MessagingService.instance.sendOneWay(message, source);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ public class StreamInSession
|
|||
if (logger.isDebugEnabled())
|
||||
logger.debug("Finished {}. Sending ack to {}", remoteFile, this);
|
||||
|
||||
Future future = CompactionManager.instance.submitSSTableBuild(localFile.desc);
|
||||
Future future = CompactionManager.instance.submitSSTableBuild(localFile.desc, remoteFile.type);
|
||||
buildFutures.add(future);
|
||||
|
||||
files.remove(remoteFile);
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ public class StreamOut
|
|||
/**
|
||||
* Split out files for all tables on disk locally for each range and then stream them to the target endpoint.
|
||||
*/
|
||||
public static void transferRanges(InetAddress target, String tableName, Collection<Range> ranges, Runnable callback)
|
||||
public static void transferRanges(InetAddress target, String tableName, Collection<Range> ranges, Runnable callback, OperationType type)
|
||||
{
|
||||
assert ranges.size() > 0;
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ public class StreamOut
|
|||
{
|
||||
Table table = flushSSTable(tableName);
|
||||
// send the matching portion of every sstable in the keyspace
|
||||
transferSSTables(session, table.getAllSSTables(), ranges);
|
||||
transferSSTables(session, table.getAllSSTables(), ranges, type);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
|
|
@ -117,7 +117,7 @@ public class StreamOut
|
|||
/**
|
||||
* Split out files for all tables on disk locally for each range and then stream them to the target endpoint.
|
||||
*/
|
||||
public static void transferRangesForRequest(StreamOutSession session, Collection<Range> ranges)
|
||||
public static void transferRangesForRequest(StreamOutSession session, Collection<Range> ranges, OperationType type)
|
||||
{
|
||||
assert ranges.size() > 0;
|
||||
|
||||
|
|
@ -128,7 +128,7 @@ public class StreamOut
|
|||
{
|
||||
Table table = flushSSTable(session.table);
|
||||
// send the matching portion of every sstable in the keyspace
|
||||
List<PendingFile> pending = createPendingFiles(table.getAllSSTables(), ranges);
|
||||
List<PendingFile> pending = createPendingFiles(table.getAllSSTables(), ranges, type);
|
||||
session.addFilesToStream(pending);
|
||||
session.begin();
|
||||
}
|
||||
|
|
@ -141,9 +141,9 @@ public class StreamOut
|
|||
/**
|
||||
* Transfers matching portions of a group of sstables from a single table to the target endpoint.
|
||||
*/
|
||||
public static void transferSSTables(StreamOutSession session, Collection<SSTableReader> sstables, Collection<Range> ranges) throws IOException
|
||||
public static void transferSSTables(StreamOutSession session, Collection<SSTableReader> sstables, Collection<Range> ranges, OperationType type) throws IOException
|
||||
{
|
||||
List<PendingFile> pending = createPendingFiles(sstables, ranges);
|
||||
List<PendingFile> pending = createPendingFiles(sstables, ranges, type);
|
||||
|
||||
if (pending.size() > 0)
|
||||
{
|
||||
|
|
@ -157,7 +157,7 @@ public class StreamOut
|
|||
}
|
||||
|
||||
// called prior to sending anything.
|
||||
private static List<PendingFile> createPendingFiles(Collection<SSTableReader> sstables, Collection<Range> ranges)
|
||||
private static List<PendingFile> createPendingFiles(Collection<SSTableReader> sstables, Collection<Range> ranges, OperationType type)
|
||||
{
|
||||
List<PendingFile> pending = new ArrayList<PendingFile>();
|
||||
for (SSTableReader sstable : sstables)
|
||||
|
|
@ -166,7 +166,7 @@ public class StreamOut
|
|||
List<Pair<Long,Long>> sections = sstable.getPositionsForRanges(ranges);
|
||||
if (sections.isEmpty())
|
||||
continue;
|
||||
pending.add(new PendingFile(sstable, desc, SSTable.COMPONENT_DATA, sections));
|
||||
pending.add(new PendingFile(sstable, desc, SSTable.COMPONENT_DATA, sections, type));
|
||||
}
|
||||
logger.info("Stream context metadata {}, {} sstables.", pending, sstables.size());
|
||||
return pending;
|
||||
|
|
|
|||
|
|
@ -66,13 +66,15 @@ class StreamRequestMessage
|
|||
// if these are specified, file shoud not be.
|
||||
protected final Collection<Range> ranges;
|
||||
protected final String table;
|
||||
protected final OperationType type;
|
||||
|
||||
StreamRequestMessage(InetAddress target, Collection<Range> ranges, String table, long sessionId)
|
||||
StreamRequestMessage(InetAddress target, Collection<Range> ranges, String table, long sessionId, OperationType type)
|
||||
{
|
||||
this.target = target;
|
||||
this.ranges = ranges;
|
||||
this.table = table;
|
||||
this.sessionId = sessionId;
|
||||
this.type = type;
|
||||
file = null;
|
||||
}
|
||||
|
||||
|
|
@ -81,6 +83,7 @@ class StreamRequestMessage
|
|||
this.target = target;
|
||||
this.file = file;
|
||||
this.sessionId = sessionId;
|
||||
this.type = file.type;
|
||||
ranges = null;
|
||||
table = null;
|
||||
}
|
||||
|
|
@ -114,6 +117,7 @@ class StreamRequestMessage
|
|||
sb.append(range);
|
||||
sb.append(" ");
|
||||
}
|
||||
sb.append(type);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -142,6 +146,7 @@ class StreamRequestMessage
|
|||
{
|
||||
AbstractBounds.serializer().serialize(range, dos);
|
||||
}
|
||||
dos.writeUTF(srm.type.name());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -164,7 +169,8 @@ class StreamRequestMessage
|
|||
{
|
||||
ranges.add((Range) AbstractBounds.serializer().deserialize(dis));
|
||||
}
|
||||
return new StreamRequestMessage(target, ranges, table, sessionId);
|
||||
OperationType type = OperationType.valueOf(dis.readUTF());
|
||||
return new StreamRequestMessage(target, ranges, table, sessionId, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public class StreamRequestVerbHandler implements IVerbHandler
|
|||
logger.debug(srm.toString());
|
||||
|
||||
StreamOutSession session = StreamOutSession.create(srm.table, message.getFrom(), srm.sessionId);
|
||||
StreamOut.transferRangesForRequest(session, srm.ranges);
|
||||
StreamOut.transferRangesForRequest(session, srm.ranges, srm.type);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
|
@ -72,6 +73,7 @@ import org.apache.cassandra.scheduler.IRequestScheduler;
|
|||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.service.StorageProxy;
|
||||
import org.apache.cassandra.service.StorageService;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.thrift.TException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
@ -269,7 +271,6 @@ public class CassandraServer implements Cassandra.Iface
|
|||
logger.debug("multiget_slice");
|
||||
|
||||
state().hasColumnFamilyAccess(column_parent.column_family, Permission.READ);
|
||||
|
||||
return multigetSliceInternal(state().getKeyspace(), keys, column_parent, predicate, consistency_level);
|
||||
}
|
||||
|
||||
|
|
@ -301,11 +302,9 @@ public class CassandraServer implements Cassandra.Iface
|
|||
return getSlice(commands, consistency_level);
|
||||
}
|
||||
|
||||
public ColumnOrSuperColumn get(ByteBuffer key, ColumnPath column_path, ConsistencyLevel consistency_level)
|
||||
private ColumnOrSuperColumn internal_get(ByteBuffer key, ColumnPath column_path, ConsistencyLevel consistency_level)
|
||||
throws InvalidRequestException, NotFoundException, UnavailableException, TimedOutException
|
||||
{
|
||||
logger.debug("get");
|
||||
|
||||
state().hasColumnFamilyAccess(column_path.column_family, Permission.READ);
|
||||
String keyspace = state().getKeyspace();
|
||||
|
||||
|
|
@ -329,6 +328,14 @@ public class CassandraServer implements Cassandra.Iface
|
|||
return tcolumns.get(0);
|
||||
}
|
||||
|
||||
public ColumnOrSuperColumn get(ByteBuffer key, ColumnPath column_path, ConsistencyLevel consistency_level)
|
||||
throws InvalidRequestException, NotFoundException, UnavailableException, TimedOutException
|
||||
{
|
||||
logger.debug("get");
|
||||
|
||||
return internal_get(key, column_path, consistency_level);
|
||||
}
|
||||
|
||||
public int get_count(ByteBuffer key, ColumnParent column_parent, SlicePredicate predicate, ConsistencyLevel consistency_level)
|
||||
throws InvalidRequestException, UnavailableException, TimedOutException
|
||||
{
|
||||
|
|
@ -356,11 +363,9 @@ public class CassandraServer implements Cassandra.Iface
|
|||
return counts;
|
||||
}
|
||||
|
||||
public void insert(ByteBuffer key, ColumnParent column_parent, Column column, ConsistencyLevel consistency_level)
|
||||
private void internal_insert(ByteBuffer key, ColumnParent column_parent, Column column, ConsistencyLevel consistency_level)
|
||||
throws InvalidRequestException, UnavailableException, TimedOutException
|
||||
{
|
||||
logger.debug("insert");
|
||||
|
||||
state().hasColumnFamilyAccess(column_parent.column_family, Permission.WRITE);
|
||||
|
||||
ThriftValidation.validateKey(key);
|
||||
|
|
@ -379,11 +384,17 @@ public class CassandraServer implements Cassandra.Iface
|
|||
doInsert(consistency_level, Arrays.asList(rm));
|
||||
}
|
||||
|
||||
public void batch_mutate(Map<ByteBuffer,Map<String,List<Mutation>>> mutation_map, ConsistencyLevel consistency_level)
|
||||
public void insert(ByteBuffer key, ColumnParent column_parent, Column column, ConsistencyLevel consistency_level)
|
||||
throws InvalidRequestException, UnavailableException, TimedOutException
|
||||
{
|
||||
logger.debug("insert");
|
||||
|
||||
internal_insert(key, column_parent, column, consistency_level);
|
||||
}
|
||||
|
||||
private void internal_batch_mutate(Map<ByteBuffer,Map<String,List<Mutation>>> mutation_map, ConsistencyLevel consistency_level)
|
||||
throws InvalidRequestException, UnavailableException, TimedOutException
|
||||
{
|
||||
logger.debug("batch_mutate");
|
||||
|
||||
List<String> cfamsSeen = new ArrayList<String>();
|
||||
|
||||
List<RowMutation> rowMutations = new ArrayList<RowMutation>();
|
||||
|
|
@ -415,11 +426,17 @@ public class CassandraServer implements Cassandra.Iface
|
|||
doInsert(consistency_level, rowMutations);
|
||||
}
|
||||
|
||||
public void remove(ByteBuffer key, ColumnPath column_path, long timestamp, ConsistencyLevel consistency_level)
|
||||
public void batch_mutate(Map<ByteBuffer,Map<String,List<Mutation>>> mutation_map, ConsistencyLevel consistency_level)
|
||||
throws InvalidRequestException, UnavailableException, TimedOutException
|
||||
{
|
||||
logger.debug("remove");
|
||||
logger.debug("batch_mutate");
|
||||
|
||||
internal_batch_mutate(mutation_map, consistency_level);
|
||||
}
|
||||
|
||||
private void internal_remove(ByteBuffer key, ColumnPath column_path, long timestamp, ConsistencyLevel consistency_level)
|
||||
throws InvalidRequestException, UnavailableException, TimedOutException
|
||||
{
|
||||
state().hasColumnFamilyAccess(column_path.column_family, Permission.WRITE);
|
||||
|
||||
ThriftValidation.validateKey(key);
|
||||
|
|
@ -431,6 +448,14 @@ public class CassandraServer implements Cassandra.Iface
|
|||
doInsert(consistency_level, Arrays.asList(rm));
|
||||
}
|
||||
|
||||
public void remove(ByteBuffer key, ColumnPath column_path, long timestamp, ConsistencyLevel consistency_level)
|
||||
throws InvalidRequestException, UnavailableException, TimedOutException
|
||||
{
|
||||
logger.debug("remove");
|
||||
|
||||
internal_remove(key, column_path, timestamp, consistency_level);
|
||||
}
|
||||
|
||||
private void doInsert(ConsistencyLevel consistency_level, List<RowMutation> mutations) throws UnavailableException, TimedOutException
|
||||
{
|
||||
try
|
||||
|
|
@ -898,6 +923,7 @@ public class CassandraServer implements Cassandra.Iface
|
|||
cf_def.row_cache_size,
|
||||
cf_def.key_cache_size,
|
||||
cf_def.read_repair_chance,
|
||||
cf_def.replicate_on_write,
|
||||
cf_def.isSetGc_grace_seconds() ? cf_def.gc_grace_seconds : CFMetaData.DEFAULT_GC_GRACE_SECONDS,
|
||||
DatabaseDescriptor.getComparator(cf_def.default_validation_class),
|
||||
cf_def.isSetMin_compaction_threshold() ? cf_def.min_compaction_threshold : CFMetaData.DEFAULT_MIN_COMPACTION_THRESHOLD,
|
||||
|
|
@ -946,5 +972,190 @@ public class CassandraServer implements Cassandra.Iface
|
|||
return StorageProxy.describeSchemaVersions();
|
||||
}
|
||||
|
||||
// counter methods
|
||||
|
||||
private Column getCounterColumn(CounterColumn column)
|
||||
{
|
||||
return new Column(column.name, FBUtilities.toByteBuffer(column.value), System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public void add(ByteBuffer key, ColumnParent column_parent, CounterColumn column, ConsistencyLevel consistency_level)
|
||||
throws InvalidRequestException, UnavailableException, TimedOutException, TException
|
||||
{
|
||||
logger.debug("add");
|
||||
|
||||
if (ConsistencyLevel.ONE != consistency_level)
|
||||
{
|
||||
throw new InvalidRequestException("Commutative CFs only support ConsistencyLevel.ONE");
|
||||
}
|
||||
|
||||
String keyspace = state().getKeyspace();
|
||||
ThriftValidation.validateCommutative(keyspace, column_parent.column_family);
|
||||
|
||||
internal_insert(key, column_parent, getCounterColumn(column), consistency_level);
|
||||
}
|
||||
|
||||
private Mutation getMutation(CounterMutation counterMutation)
|
||||
{
|
||||
Mutation mutation = new Mutation();
|
||||
|
||||
if (counterMutation.isSetCounter())
|
||||
{
|
||||
Counter counter = counterMutation.counter;
|
||||
ColumnOrSuperColumn cosc = new ColumnOrSuperColumn();
|
||||
if (counter.isSetColumn())
|
||||
{
|
||||
Column c = new Column(counter.column.name, FBUtilities.toByteBuffer(counter.column.value), System.currentTimeMillis());
|
||||
cosc.setColumn(c);
|
||||
}
|
||||
|
||||
if (counter.isSetSuper_column())
|
||||
{
|
||||
List<Column> subcolumns = new ArrayList<Column>(counter.super_column.columns.size());
|
||||
for (CounterColumn subcol : counter.super_column.columns)
|
||||
{
|
||||
subcolumns.add(new Column(subcol.name, FBUtilities.toByteBuffer(subcol.value), System.currentTimeMillis()));
|
||||
}
|
||||
SuperColumn sc = new SuperColumn(counter.super_column.name, subcolumns);
|
||||
cosc.setSuper_column(sc);
|
||||
}
|
||||
mutation.setColumn_or_supercolumn(cosc);
|
||||
}
|
||||
|
||||
if (counterMutation.isSetDeletion())
|
||||
{
|
||||
Deletion deletion = new Deletion(System.currentTimeMillis());
|
||||
if (counterMutation.deletion.isSetSuper_column())
|
||||
deletion.setSuper_column(counterMutation.deletion.super_column);
|
||||
if (counterMutation.deletion.isSetPredicate())
|
||||
deletion.setPredicate(counterMutation.deletion.predicate);
|
||||
mutation.setDeletion(deletion);
|
||||
}
|
||||
|
||||
return mutation;
|
||||
}
|
||||
|
||||
public void batch_add(Map<ByteBuffer, Map<String, List<CounterMutation>>> updateMap, ConsistencyLevel consistency_level)
|
||||
throws InvalidRequestException, UnavailableException, TimedOutException, TException
|
||||
{
|
||||
logger.debug("batch_add");
|
||||
|
||||
if (ConsistencyLevel.ONE != consistency_level)
|
||||
{
|
||||
throw new InvalidRequestException("Commutative CFs only support ConsistencyLevel.ONE");
|
||||
}
|
||||
|
||||
String keyspace = state().getKeyspace();
|
||||
|
||||
Map<ByteBuffer,Map<String,List<Mutation>>> mutation_map = new HashMap<ByteBuffer,Map<String,List<Mutation>>>();
|
||||
|
||||
for (Entry<ByteBuffer, Map<String, List<CounterMutation>>> entry : updateMap.entrySet())
|
||||
{
|
||||
Map<String, List<Mutation>> valueMap = new HashMap<String, List<Mutation>>(entry.getValue().size());
|
||||
|
||||
for (Entry<String, List<CounterMutation>> innerEntry : entry.getValue().entrySet())
|
||||
{
|
||||
ThriftValidation.validateCommutative(keyspace, innerEntry.getKey());
|
||||
|
||||
List<Mutation> mutations = new ArrayList<Mutation>(innerEntry.getValue().size());
|
||||
for (CounterMutation cm : innerEntry.getValue())
|
||||
{
|
||||
mutations.add(getMutation(cm));
|
||||
}
|
||||
valueMap.put(innerEntry.getKey(), mutations);
|
||||
}
|
||||
|
||||
mutation_map.put(entry.getKey(), valueMap);
|
||||
}
|
||||
|
||||
internal_batch_mutate(mutation_map, consistency_level);
|
||||
}
|
||||
|
||||
private Counter getCounter(ColumnOrSuperColumn cosc)
|
||||
{
|
||||
if (cosc.isSetColumn()) {
|
||||
return new Counter().setColumn(new CounterColumn(cosc.column.name, cosc.column.value.getLong(cosc.column.value.arrayOffset())));
|
||||
} else if(cosc.isSetSuper_column()) {
|
||||
List<CounterColumn> cc = new ArrayList<CounterColumn>(cosc.super_column.columns.size());
|
||||
for (Column col : cosc.super_column.columns)
|
||||
{
|
||||
cc.add(new CounterColumn(col.name, col.value.getLong(col.value.arrayOffset())));
|
||||
}
|
||||
return new Counter().setSuper_column(new CounterSuperColumn(cosc.super_column.name, cc));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Counter get_counter(ByteBuffer key, ColumnPath path, ConsistencyLevel consistency_level)
|
||||
throws InvalidRequestException, NotFoundException, UnavailableException, TimedOutException, TException
|
||||
{
|
||||
logger.debug("get_counter");
|
||||
|
||||
String keyspace = state().getKeyspace();
|
||||
ThriftValidation.validateCommutative(keyspace, path.column_family);
|
||||
|
||||
return getCounter(internal_get(key, path, consistency_level));
|
||||
}
|
||||
|
||||
private List<Counter> getCounters(List<ColumnOrSuperColumn> cosc)
|
||||
{
|
||||
List<Counter> rv = new ArrayList<Counter>(cosc.size());
|
||||
for (ColumnOrSuperColumn columnOrSuperColumn : cosc)
|
||||
{
|
||||
Counter c = getCounter(columnOrSuperColumn);
|
||||
if (c != null) {
|
||||
rv.add(c);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
public List<Counter> get_counter_slice(ByteBuffer key, ColumnParent column_parent, SlicePredicate predicate,
|
||||
ConsistencyLevel consistency_level) throws InvalidRequestException, UnavailableException, TimedOutException,
|
||||
TException
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("get_counter_slice");
|
||||
|
||||
String keyspace = state().getKeyspace();
|
||||
ThriftValidation.validateCommutative(keyspace, column_parent.column_family);
|
||||
|
||||
state().hasColumnFamilyAccess(column_parent.column_family, Permission.READ);
|
||||
List<ColumnOrSuperColumn> cosc = multigetSliceInternal(state().getKeyspace(), Collections.singletonList(key), column_parent, predicate, consistency_level).get(key);
|
||||
return getCounters(cosc);
|
||||
}
|
||||
|
||||
public Map<ByteBuffer, List<Counter>> multiget_counter_slice(List<ByteBuffer> keys, ColumnParent column_parent,
|
||||
SlicePredicate predicate, ConsistencyLevel consistency_level) throws InvalidRequestException,
|
||||
UnavailableException, TimedOutException, TException
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("multiget_counter_slice");
|
||||
|
||||
String keyspace = state().getKeyspace();
|
||||
ThriftValidation.validateCommutative(keyspace, column_parent.column_family);
|
||||
|
||||
state().hasColumnFamilyAccess(column_parent.column_family, Permission.READ);
|
||||
Map<ByteBuffer, List<ColumnOrSuperColumn>> slices = multigetSliceInternal(state().getKeyspace(), keys, column_parent, predicate, consistency_level);
|
||||
Map<ByteBuffer, List<Counter>> rv = new HashMap<ByteBuffer, List<Counter>>(slices.size());
|
||||
for (Entry<ByteBuffer, List<ColumnOrSuperColumn>> entry : slices.entrySet())
|
||||
{
|
||||
rv.put(entry.getKey(), getCounters(entry.getValue()));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
public void remove_counter(ByteBuffer key, ColumnPath path, ConsistencyLevel consistency_level)
|
||||
throws InvalidRequestException, UnavailableException, TimedOutException, TException
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("remove_counter");
|
||||
|
||||
String keyspace = state().getKeyspace();
|
||||
ThriftValidation.validateCommutative(keyspace, path.column_family);
|
||||
|
||||
internal_remove(key, path, System.currentTimeMillis(), consistency_level);
|
||||
}
|
||||
|
||||
// main method moved to CassandraDaemon
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import java.util.Arrays;
|
|||
import java.util.Comparator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.config.ConfigurationException;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.db.ColumnFamily;
|
||||
|
|
@ -432,4 +433,28 @@ public class ThriftValidation
|
|||
throw new InvalidRequestException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static CFMetaData validateCFMetaData(String tablename, String cfName) throws InvalidRequestException
|
||||
{
|
||||
if (cfName.isEmpty())
|
||||
{
|
||||
throw new InvalidRequestException("non-empty columnfamily is required");
|
||||
}
|
||||
CFMetaData metadata = DatabaseDescriptor.getCFMetaData(tablename, cfName);
|
||||
if (metadata == null)
|
||||
{
|
||||
throw new InvalidRequestException("unconfigured columnfamily " + cfName);
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
|
||||
static void validateCommutative(String tablename, String cfName) throws InvalidRequestException
|
||||
{
|
||||
validateTable(tablename);
|
||||
CFMetaData metadata = validateCFMetaData(tablename, cfName);
|
||||
if (!metadata.getDefaultValidator().isCommutative())
|
||||
{
|
||||
throw new InvalidRequestException("not commutative columnfamily " + cfName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,6 +152,70 @@ public class FBUtilities
|
|||
return new Pair(midpoint, remainder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy bytes from int into bytes starting from offset.
|
||||
* @param bytes Target array
|
||||
* @param offset Offset into the array
|
||||
* @param i Value to write
|
||||
*/
|
||||
public static void copyIntoBytes(byte[] bytes, int offset, int i)
|
||||
{
|
||||
bytes[offset] = (byte)( ( i >>> 24 ) & 0xFF );
|
||||
bytes[offset+1] = (byte)( ( i >>> 16 ) & 0xFF );
|
||||
bytes[offset+2] = (byte)( ( i >>> 8 ) & 0xFF );
|
||||
bytes[offset+3] = (byte)( i & 0xFF );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param i Write this int to an array
|
||||
* @return 4-byte array containing the int
|
||||
*/
|
||||
public static byte[] toByteArray(int i)
|
||||
{
|
||||
byte[] bytes = new byte[4];
|
||||
copyIntoBytes(bytes, 0, i);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bytes A byte array containing a serialized integer.
|
||||
* @param offset Start position of the integer in the array.
|
||||
* @return The integer value contained in the byte array.
|
||||
*/
|
||||
public static int byteArrayToInt(byte[] bytes, int offset)
|
||||
{
|
||||
if (bytes.length - offset < 4)
|
||||
{
|
||||
throw new IllegalArgumentException("An integer must be 4 bytes in size.");
|
||||
}
|
||||
int n = 0;
|
||||
for ( int i = 0; i < 4; ++i )
|
||||
{
|
||||
n <<= 8;
|
||||
n |= bytes[offset + i] & 0xFF;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a byte buffer to an integer.
|
||||
* Does not change the byte buffer position.
|
||||
*/
|
||||
public static int byteBufferToInt(ByteBuffer bytes)
|
||||
{
|
||||
if (bytes.remaining() < 4)
|
||||
{
|
||||
throw new IllegalArgumentException("An integer must be 4 bytes in size.");
|
||||
}
|
||||
int n = 0;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
n <<= 8;
|
||||
n |= bytes.array()[bytes.position() + bytes.arrayOffset() + i] & 0xFF;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
public static ByteBuffer toByteBuffer(int i)
|
||||
{
|
||||
byte[] bytes = new byte[4];
|
||||
|
|
@ -162,21 +226,71 @@ public class FBUtilities
|
|||
return ByteBuffer.wrap(bytes);
|
||||
}
|
||||
|
||||
public static int byteBufferToInt(ByteBuffer bytes)
|
||||
/**
|
||||
* Copy bytes from long into bytes starting from offset.
|
||||
* @param bytes Target array
|
||||
* @param offset Offset into the array
|
||||
* @param l Value to write
|
||||
*/
|
||||
public static void copyIntoBytes(byte[] bytes, int offset, long l)
|
||||
{
|
||||
if (bytes.remaining() < 4 )
|
||||
bytes[offset] = (byte)( ( l >>> 56 ) & 0xFF );
|
||||
bytes[offset+1] = (byte)( ( l >>> 48 ) & 0xFF );
|
||||
bytes[offset+2] = (byte)( ( l >>> 40 ) & 0xFF );
|
||||
bytes[offset+3] = (byte)( ( l >>> 32 ) & 0xFF );
|
||||
bytes[offset+4] = (byte)( ( l >>> 24 ) & 0xFF );
|
||||
bytes[offset+5] = (byte)( ( l >>> 16 ) & 0xFF );
|
||||
bytes[offset+6] = (byte)( ( l >>> 8 ) & 0xFF );
|
||||
bytes[offset+7] = (byte)( l & 0xFF );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param l Write this long to an array
|
||||
* @return 8-byte array containing the long
|
||||
*/
|
||||
public static byte[] toByteArray(long l)
|
||||
{
|
||||
byte[] bytes = new byte[8];
|
||||
copyIntoBytes(bytes, 0, l);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bytes A byte array containing a serialized long.
|
||||
* @return The long value contained in the byte array.
|
||||
*/
|
||||
public static long byteArrayToLong(byte[] bytes)
|
||||
{
|
||||
return byteArrayToLong(bytes, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bytes A byte array containing a serialized long.
|
||||
* @param offset Start position of the long in the array.
|
||||
* @return The long value contained in the byte array.
|
||||
*/
|
||||
public static long byteArrayToLong(byte[] bytes, int offset)
|
||||
{
|
||||
if (bytes.length - offset < 8)
|
||||
{
|
||||
throw new IllegalArgumentException("An integer must be 4 bytes in size.");
|
||||
throw new IllegalArgumentException("A long must be 8 bytes in size.");
|
||||
}
|
||||
int n = 0;
|
||||
for ( int i = 0; i < 4; ++i )
|
||||
long n = 0;
|
||||
for ( int i = 0; i < 8; ++i )
|
||||
{
|
||||
n <<= 8;
|
||||
n |= bytes.array()[bytes.position() + bytes.arrayOffset() + i] & 0xFF;
|
||||
n |= bytes[offset + i] & 0xFF;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
public static ByteBuffer toByteBuffer(long n)
|
||||
{
|
||||
byte[] bytes = new byte[8];
|
||||
ByteBuffer bb = ByteBuffer.wrap(bytes).putLong(0, n);
|
||||
return bb;
|
||||
}
|
||||
|
||||
public static int compareUnsigned(byte[] bytes1, byte[] bytes2, int offset1, int offset2, int len1, int len2)
|
||||
{
|
||||
if (bytes1 == null)
|
||||
|
|
@ -196,6 +310,38 @@ public class FBUtilities
|
|||
if ((len1 - offset1) == (len2 - offset2)) return 0;
|
||||
else return ((len1 - offset1) < (len2 - offset2)) ? -1 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two byte[] at specified offsets for length. Compares the non equal bytes as unsigned.
|
||||
* @param bytes1 First array to compare.
|
||||
* @param offset1 Position to start the comparison at in the first array.
|
||||
* @param bytes2 Second array to compare.
|
||||
* @param offset2 Position to start the comparison at in the second array.
|
||||
* @param length How many bytes to compare?
|
||||
* @return -1 if byte1 is less than byte2, 1 if byte2 is less than byte1 or 0 if equal.
|
||||
*/
|
||||
public static int compareByteSubArrays(byte[] bytes1, int offset1, byte[] bytes2, int offset2, int length)
|
||||
{
|
||||
if ( null == bytes1 )
|
||||
{
|
||||
if ( null == bytes2) return 0;
|
||||
else return -1;
|
||||
}
|
||||
if (null == bytes2 ) return 1;
|
||||
|
||||
assert bytes1.length >= (offset1 + length) : "The first byte array isn't long enough for the specified offset and length.";
|
||||
assert bytes2.length >= (offset2 + length) : "The second byte array isn't long enough for the specified offset and length.";
|
||||
for ( int i = 0; i < length; i++ )
|
||||
{
|
||||
byte byte1 = bytes1[offset1+i];
|
||||
byte byte2 = bytes2[offset2+i];
|
||||
if ( byte1 == byte2 )
|
||||
continue;
|
||||
// compare non-equal bytes as unsigned
|
||||
return (byte1 & 0xFF) < (byte2 & 0xFF) ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The bitwise XOR of the inputs. The output will be the same length as the
|
||||
|
|
@ -496,12 +642,41 @@ public class FBUtilities
|
|||
return decoded;
|
||||
}
|
||||
|
||||
public static ByteBuffer toByteBuffer(long n)
|
||||
/**
|
||||
* Thin wrapper around byte[] to provide meaningful equals() and hashCode() operations
|
||||
* caveat: assumed that wrapped byte[] will not be modified
|
||||
*/
|
||||
public static final class ByteArrayWrapper
|
||||
{
|
||||
byte[] bytes = new byte[8];
|
||||
ByteBuffer bb = ByteBuffer.wrap(bytes).putLong(n);
|
||||
bb.rewind();
|
||||
return bb;
|
||||
public final byte[] data;
|
||||
|
||||
public ByteArrayWrapper(byte[] data)
|
||||
{
|
||||
if ( null == data )
|
||||
{
|
||||
throw new NullPointerException();
|
||||
}
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public boolean equals(Object other)
|
||||
{
|
||||
if ( !( other instanceof ByteArrayWrapper ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Arrays.equals(data, ((ByteArrayWrapper)other).data);
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return Arrays.hashCode(data);
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return ArrayUtils.toString(data);
|
||||
}
|
||||
}
|
||||
|
||||
public static String resourceToFile(String filename) throws ConfigurationException
|
||||
|
|
@ -519,6 +694,10 @@ public class FBUtilities
|
|||
try
|
||||
{
|
||||
InputStream in = FBUtilities.class.getClassLoader().getResourceAsStream("org/apache/cassandra/config/version.properties");
|
||||
if (in == null)
|
||||
{
|
||||
return "Unknown";
|
||||
}
|
||||
Properties props = new Properties();
|
||||
props.load(in);
|
||||
return props.getProperty("CassandraVersion");
|
||||
|
|
|
|||
|
|
@ -70,6 +70,14 @@ keyspaces:
|
|||
column_type: Super
|
||||
compare_subcolumns_with: UTF8Type
|
||||
|
||||
- name: Counter1
|
||||
column_type: Standard
|
||||
default_validation_class: CounterColumnType
|
||||
|
||||
- name: SuperCounter1
|
||||
column_type: Super
|
||||
default_validation_class: CounterColumnType
|
||||
|
||||
- name: Indexed1
|
||||
column_metadata:
|
||||
- name: birthdate
|
||||
|
|
@ -135,3 +143,7 @@ keyspaces:
|
|||
replication_factor: 2
|
||||
column_families:
|
||||
- name: Standard1
|
||||
|
||||
- name: Counter1
|
||||
column_type: Standard
|
||||
default_validation_class: CounterColumnType
|
||||
|
|
|
|||
|
|
@ -170,6 +170,8 @@ class ThriftTester(BaseTester):
|
|||
Cassandra.CfDef('Keyspace1', 'Super2', column_type='Super', subcomparator_type='LongType'),
|
||||
Cassandra.CfDef('Keyspace1', 'Super3', column_type='Super', subcomparator_type='LongType'),
|
||||
Cassandra.CfDef('Keyspace1', 'Super4', column_type='Super', subcomparator_type='UTF8Type'),
|
||||
Cassandra.CfDef('Keyspace1', 'Counter1', default_validation_class='CounterColumnType'),
|
||||
Cassandra.CfDef('Keyspace1', 'SuperCounter1', column_type='Super', default_validation_class='CounterColumnType'),
|
||||
Cassandra.CfDef('Keyspace1', 'Indexed1', column_metadata=[Cassandra.ColumnDef('birthdate', 'LongType', Cassandra.IndexType.KEYS, 'birthdate')]),
|
||||
])
|
||||
|
||||
|
|
|
|||
|
|
@ -1467,6 +1467,255 @@ class TestMutations(ThriftTester):
|
|||
client.describe_ring('system')
|
||||
_expect_exception(req, InvalidRequestException)
|
||||
|
||||
def test_incr_decr_standard_add(self):
|
||||
_set_keyspace('Keyspace1')
|
||||
|
||||
d1 = 12
|
||||
d2 = -21
|
||||
d3 = 35
|
||||
# insert positive and negative values and check the counts
|
||||
client.add('key1', ColumnParent(column_family='Counter1'), CounterColumn('c1', d1), ConsistencyLevel.ONE)
|
||||
time.sleep(0.1)
|
||||
rv1 = client.get_counter('key1', ColumnPath(column_family='Counter1', column='c1'), ConsistencyLevel.ONE)
|
||||
assert rv1.column.value == d1
|
||||
|
||||
client.add('key1', ColumnParent(column_family='Counter1'), CounterColumn('c1', d2), ConsistencyLevel.ONE)
|
||||
time.sleep(0.1)
|
||||
rv2 = client.get_counter('key1', ColumnPath(column_family='Counter1', column='c1'), ConsistencyLevel.ONE)
|
||||
assert rv2.column.value == (d1+d2)
|
||||
|
||||
client.add('key1', ColumnParent(column_family='Counter1'), CounterColumn('c1', d3), ConsistencyLevel.ONE)
|
||||
time.sleep(0.1)
|
||||
rv3 = client.get_counter('key1', ColumnPath(column_family='Counter1', column='c1'), ConsistencyLevel.ONE)
|
||||
assert rv3.column.value == (d1+d2+d3)
|
||||
|
||||
def test_incr_decr_super_add(self):
|
||||
_set_keyspace('Keyspace1')
|
||||
|
||||
d1 = -234
|
||||
d2 = 52345
|
||||
d3 = 3123
|
||||
|
||||
client.add('key1', ColumnParent(column_family='SuperCounter1', super_column='sc1'), CounterColumn('c1', d1), ConsistencyLevel.ONE)
|
||||
client.add('key1', ColumnParent(column_family='SuperCounter1', super_column='sc1'), CounterColumn('c2', d2), ConsistencyLevel.ONE)
|
||||
time.sleep(0.1)
|
||||
rv1 = client.get_counter('key1', ColumnPath(column_family='SuperCounter1', super_column='sc1'), ConsistencyLevel.ONE)
|
||||
assert rv1.super_column.columns[0].value == d1
|
||||
assert rv1.super_column.columns[1].value == d2
|
||||
|
||||
client.add('key1', ColumnParent(column_family='SuperCounter1', super_column='sc1'), CounterColumn('c1', d2), ConsistencyLevel.ONE)
|
||||
time.sleep(0.1)
|
||||
rv2 = client.get_counter('key1', ColumnPath('SuperCounter1', 'sc1', 'c1'), ConsistencyLevel.ONE)
|
||||
assert rv2.column.value == (d1+d2)
|
||||
|
||||
client.add('key1', ColumnParent(column_family='SuperCounter1', super_column='sc1'), CounterColumn('c1', d3), ConsistencyLevel.ONE)
|
||||
time.sleep(0.1)
|
||||
rv3 = client.get_counter('key1', ColumnPath(column_family='SuperCounter1', super_column='sc1', column='c1'), ConsistencyLevel.ONE)
|
||||
assert rv3.column.value == (d1+d2+d3)
|
||||
|
||||
def test_incr_standard_remove(self):
|
||||
_set_keyspace('Keyspace1')
|
||||
|
||||
d1 = 124
|
||||
|
||||
# insert value and check it exists
|
||||
client.add('key1', ColumnParent(column_family='Counter1'), CounterColumn('c1', d1), ConsistencyLevel.ONE)
|
||||
time.sleep(5)
|
||||
rv1 = client.get_counter('key1', ColumnPath(column_family='Counter1', column='c1'), ConsistencyLevel.ONE)
|
||||
assert rv1.column.value == d1
|
||||
|
||||
# remove the previous column and check that it is gone
|
||||
client.remove_counter('key1', ColumnPath(column_family='Counter1', column='c1'), ConsistencyLevel.ONE)
|
||||
time.sleep(5)
|
||||
_assert_no_columnpath('key1', ColumnPath(column_family='Counter1', column='c1'))
|
||||
|
||||
# insert again and this time delete the whole row, check that it is gone
|
||||
client.add('key1', ColumnParent(column_family='Counter1'), CounterColumn('c1', d1), ConsistencyLevel.ONE)
|
||||
time.sleep(5)
|
||||
rv2 = client.get_counter('key1', ColumnPath(column_family='Counter1', column='c1'), ConsistencyLevel.ONE)
|
||||
assert rv2.column.value == d1
|
||||
client.remove_counter('key1', ColumnPath(column_family='Counter1'), ConsistencyLevel.ONE)
|
||||
time.sleep(5)
|
||||
_assert_no_columnpath('key1', ColumnPath(column_family='Counter1', column='c1'))
|
||||
|
||||
def test_incr_super_remove(self):
|
||||
_set_keyspace('Keyspace1')
|
||||
|
||||
d1 = 52345
|
||||
|
||||
# insert value and check it exists
|
||||
client.add('key1', ColumnParent(column_family='SuperCounter1', super_column='sc1'), CounterColumn('c1', d1), ConsistencyLevel.ONE)
|
||||
time.sleep(5)
|
||||
rv1 = client.get_counter('key1', ColumnPath(column_family='SuperCounter1', super_column='sc1', column='c1'), ConsistencyLevel.ONE)
|
||||
assert rv1.column.value == d1
|
||||
|
||||
# remove the previous column and check that it is gone
|
||||
client.remove_counter('key1', ColumnPath(column_family='SuperCounter1', super_column='sc1', column='c1'), ConsistencyLevel.ONE)
|
||||
time.sleep(5)
|
||||
_assert_no_columnpath('key1', ColumnPath(column_family='SuperCounter1', super_column='sc1', column='c1'))
|
||||
|
||||
# insert again and this time delete the whole row, check that it is gone
|
||||
client.add('key1', ColumnParent(column_family='SuperCounter1', super_column='sc1'), CounterColumn('c1', d1), ConsistencyLevel.ONE)
|
||||
time.sleep(5)
|
||||
rv2 = client.get_counter('key1', ColumnPath(column_family='SuperCounter1', super_column='sc1', column='c1'), ConsistencyLevel.ONE)
|
||||
assert rv2.column.value == d1
|
||||
client.remove_counter('key1', ColumnPath(column_family='SuperCounter1', super_column='sc1'), ConsistencyLevel.ONE)
|
||||
time.sleep(5)
|
||||
_assert_no_columnpath('key1', ColumnPath(column_family='SuperCounter1', super_column='sc1', column='c1'))
|
||||
|
||||
def test_incr_decr_standard_remove(self):
|
||||
_set_keyspace('Keyspace1')
|
||||
|
||||
d1 = 124
|
||||
|
||||
# insert value and check it exists
|
||||
client.add('key1', ColumnParent(column_family='Counter1'), CounterColumn('c1', d1), ConsistencyLevel.ONE)
|
||||
time.sleep(5)
|
||||
rv1 = client.get_counter('key1', ColumnPath(column_family='Counter1', column='c1'), ConsistencyLevel.ONE)
|
||||
assert rv1.column.value == d1
|
||||
|
||||
# remove the previous column and check that it is gone
|
||||
client.remove_counter('key1', ColumnPath(column_family='Counter1', column='c1'), ConsistencyLevel.ONE)
|
||||
time.sleep(5)
|
||||
_assert_no_columnpath('key1', ColumnPath(column_family='Counter1', column='c1'))
|
||||
|
||||
# insert again and this time delete the whole row, check that it is gone
|
||||
client.add('key1', ColumnParent(column_family='Counter1'), CounterColumn('c1', d1), ConsistencyLevel.ONE)
|
||||
time.sleep(5)
|
||||
rv2 = client.get_counter('key1', ColumnPath(column_family='Counter1', column='c1'), ConsistencyLevel.ONE)
|
||||
assert rv2.column.value == d1
|
||||
client.remove_counter('key1', ColumnPath(column_family='Counter1'), ConsistencyLevel.ONE)
|
||||
time.sleep(5)
|
||||
_assert_no_columnpath('key1', ColumnPath(column_family='Counter1', column='c1'))
|
||||
|
||||
def test_incr_decr_super_remove(self):
|
||||
_set_keyspace('Keyspace1')
|
||||
|
||||
d1 = 52345
|
||||
|
||||
# insert value and check it exists
|
||||
client.add('key1', ColumnParent(column_family='SuperCounter1', super_column='sc1'), CounterColumn('c1', d1), ConsistencyLevel.ONE)
|
||||
time.sleep(5)
|
||||
rv1 = client.get_counter('key1', ColumnPath(column_family='SuperCounter1', super_column='sc1', column='c1'), ConsistencyLevel.ONE)
|
||||
assert rv1.column.value == d1
|
||||
|
||||
# remove the previous column and check that it is gone
|
||||
client.remove_counter('key1', ColumnPath(column_family='SuperCounter1', super_column='sc1', column='c1'), ConsistencyLevel.ONE)
|
||||
time.sleep(5)
|
||||
_assert_no_columnpath('key1', ColumnPath(column_family='SuperCounter1', super_column='sc1', column='c1'))
|
||||
|
||||
# insert again and this time delete the whole row, check that it is gone
|
||||
client.add('key1', ColumnParent(column_family='SuperCounter1', super_column='sc1'), CounterColumn('c1', d1), ConsistencyLevel.ONE)
|
||||
time.sleep(5)
|
||||
rv2 = client.get_counter('key1', ColumnPath(column_family='SuperCounter1', super_column='sc1', column='c1'), ConsistencyLevel.ONE)
|
||||
assert rv2.column.value == d1
|
||||
client.remove_counter('key1', ColumnPath(column_family='SuperCounter1', super_column='sc1'), ConsistencyLevel.ONE)
|
||||
time.sleep(5)
|
||||
_assert_no_columnpath('key1', ColumnPath(column_family='SuperCounter1', super_column='sc1', column='c1'))
|
||||
|
||||
def test_incr_decr_standard_batch_add(self):
|
||||
_set_keyspace('Keyspace1')
|
||||
|
||||
d1 = 12
|
||||
d2 = -21
|
||||
update_map = {'key1': {'Counter1': [
|
||||
CounterMutation(counter=Counter(column=CounterColumn('c1', d1))),
|
||||
CounterMutation(counter=Counter(column=CounterColumn('c1', d2))),
|
||||
]}}
|
||||
|
||||
# insert positive and negative values and check the counts
|
||||
client.batch_add(update_map, ConsistencyLevel.ONE)
|
||||
time.sleep(0.1)
|
||||
rv1 = client.get_counter('key1', ColumnPath(column_family='Counter1', column='c1'), ConsistencyLevel.ONE)
|
||||
assert rv1.column.value == d1+d2
|
||||
|
||||
def test_incr_decr_standard_batch_remove(self):
|
||||
_set_keyspace('Keyspace1')
|
||||
|
||||
d1 = 12
|
||||
d2 = -21
|
||||
|
||||
# insert positive and negative values and check the counts
|
||||
update_map = {'key1': {'Counter1': [
|
||||
CounterMutation(counter=Counter(column=CounterColumn('c1', d1))),
|
||||
CounterMutation(counter=Counter(column=CounterColumn('c1', d2))),
|
||||
]}}
|
||||
client.batch_add(update_map, ConsistencyLevel.ONE)
|
||||
time.sleep(5)
|
||||
rv1 = client.get_counter('key1', ColumnPath(column_family='Counter1', column='c1'), ConsistencyLevel.ONE)
|
||||
assert rv1.column.value == d1+d2
|
||||
|
||||
# remove the previous column and check that it is gone
|
||||
update_map = {'key1': {'Counter1': [
|
||||
CounterMutation(deletion=CounterDeletion(predicate=SlicePredicate(column_names=['c1']))),
|
||||
]}}
|
||||
client.batch_add(update_map, ConsistencyLevel.ONE)
|
||||
time.sleep(5)
|
||||
_assert_no_columnpath('key1', ColumnPath(column_family='Counter1', column='c1'))
|
||||
|
||||
# insert again and this time delete the whole row, check that it is gone
|
||||
update_map = {'key1': {'Counter1': [
|
||||
CounterMutation(counter=Counter(column=CounterColumn('c1', d1))),
|
||||
CounterMutation(counter=Counter(column=CounterColumn('c1', d2))),
|
||||
]}}
|
||||
client.batch_add(update_map, ConsistencyLevel.ONE)
|
||||
time.sleep(5)
|
||||
rv2 = client.get_counter('key1', ColumnPath(column_family='Counter1', column='c1'), ConsistencyLevel.ONE)
|
||||
assert rv2.column.value == d1+d2
|
||||
|
||||
update_map = {'key1': {'Counter1': [
|
||||
CounterMutation(deletion=CounterDeletion()),
|
||||
]}}
|
||||
client.batch_add(update_map, ConsistencyLevel.ONE)
|
||||
time.sleep(5)
|
||||
_assert_no_columnpath('key1', ColumnPath(column_family='Counter1', column='c1'))
|
||||
|
||||
def test_incr_decr_standard_slice(self):
|
||||
_set_keyspace('Keyspace1')
|
||||
|
||||
d1 = 12
|
||||
d2 = -21
|
||||
client.add('key1', ColumnParent(column_family='Counter1'), CounterColumn('c1', d1), ConsistencyLevel.ONE)
|
||||
client.add('key1', ColumnParent(column_family='Counter1'), CounterColumn('c2', d1), ConsistencyLevel.ONE)
|
||||
client.add('key1', ColumnParent(column_family='Counter1'), CounterColumn('c3', d1), ConsistencyLevel.ONE)
|
||||
client.add('key1', ColumnParent(column_family='Counter1'), CounterColumn('c3', d2), ConsistencyLevel.ONE)
|
||||
client.add('key1', ColumnParent(column_family='Counter1'), CounterColumn('c4', d1), ConsistencyLevel.ONE)
|
||||
client.add('key1', ColumnParent(column_family='Counter1'), CounterColumn('c5', d1), ConsistencyLevel.ONE)
|
||||
|
||||
time.sleep(0.1)
|
||||
# insert positive and negative values and check the counts
|
||||
counters = client.get_counter_slice('key1', ColumnParent('Counter1'), SlicePredicate(['c3', 'c4']), ConsistencyLevel.ONE)
|
||||
|
||||
assert counters[0].column.value == d1+d2
|
||||
assert counters[1].column.value == d1
|
||||
|
||||
def test_incr_decr_standard_muliget_slice(self):
|
||||
_set_keyspace('Keyspace1')
|
||||
|
||||
d1 = 12
|
||||
d2 = -21
|
||||
client.add('key1', ColumnParent(column_family='Counter1'), CounterColumn('c2', d1), ConsistencyLevel.ONE)
|
||||
client.add('key1', ColumnParent(column_family='Counter1'), CounterColumn('c3', d1), ConsistencyLevel.ONE)
|
||||
client.add('key1', ColumnParent(column_family='Counter1'), CounterColumn('c3', d2), ConsistencyLevel.ONE)
|
||||
client.add('key1', ColumnParent(column_family='Counter1'), CounterColumn('c4', d1), ConsistencyLevel.ONE)
|
||||
client.add('key1', ColumnParent(column_family='Counter1'), CounterColumn('c5', d1), ConsistencyLevel.ONE)
|
||||
|
||||
client.add('key2', ColumnParent(column_family='Counter1'), CounterColumn('c2', d1), ConsistencyLevel.ONE)
|
||||
client.add('key2', ColumnParent(column_family='Counter1'), CounterColumn('c3', d1), ConsistencyLevel.ONE)
|
||||
client.add('key2', ColumnParent(column_family='Counter1'), CounterColumn('c3', d2), ConsistencyLevel.ONE)
|
||||
client.add('key2', ColumnParent(column_family='Counter1'), CounterColumn('c4', d1), ConsistencyLevel.ONE)
|
||||
client.add('key2', ColumnParent(column_family='Counter1'), CounterColumn('c5', d1), ConsistencyLevel.ONE)
|
||||
|
||||
|
||||
time.sleep(0.1)
|
||||
# insert positive and negative values and check the counts
|
||||
counters = client.multiget_counter_slice(['key1', 'key2'], ColumnParent('Counter1'), SlicePredicate(['c3', 'c4']), ConsistencyLevel.ONE)
|
||||
|
||||
assert counters['key1'][0].column.value == d1+d2
|
||||
assert counters['key1'][1].column.value == d1
|
||||
assert counters['key2'][0].column.value == d1+d2
|
||||
assert counters['key2'][1].column.value == d1
|
||||
|
||||
def test_index_scan(self):
|
||||
_set_keyspace('Keyspace1')
|
||||
client.insert('key1', ColumnParent('Indexed1'), Column('birthdate', _i64(1), 0), ConsistencyLevel.ONE)
|
||||
|
|
|
|||
|
|
@ -128,6 +128,27 @@ public class Util
|
|||
return cfStore.getColumnFamily(QueryFilter.getIdentityFilter(key, new QueryPath(cfName)));
|
||||
}
|
||||
|
||||
public static byte[] concatByteArrays(byte[] first, byte[]... remaining)
|
||||
{
|
||||
int length = first.length;
|
||||
for (byte[] array : remaining)
|
||||
{
|
||||
length += array.length;
|
||||
}
|
||||
|
||||
byte[] result = new byte[length];
|
||||
System.arraycopy(first, 0, result, 0, first.length);
|
||||
int offset = first.length;
|
||||
|
||||
for (byte[] array : remaining)
|
||||
{
|
||||
System.arraycopy(array, 0, result, offset, array.length);
|
||||
offset += array.length;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static ColumnFamily cloneAndRemoveDeleted(ColumnFamily cf, int gcBefore)
|
||||
{
|
||||
return ColumnFamilyStore.removeDeleted(cf.cloneMe(), gcBefore);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,346 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
package org.apache.cassandra.db;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.cassandra.Util;
|
||||
import org.apache.cassandra.db.context.CounterContext;
|
||||
import org.apache.cassandra.db.marshal.AbstractCommutativeType;
|
||||
import org.apache.cassandra.db.marshal.CounterColumnType;
|
||||
import org.apache.cassandra.io.util.DataOutputBuffer;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
||||
public class CounterColumnTest
|
||||
{
|
||||
private static final CounterContext cc = new CounterContext();
|
||||
|
||||
private static final int idLength;
|
||||
private static final int clockLength;
|
||||
private static final int countLength;
|
||||
|
||||
private static final int stepLength;
|
||||
|
||||
static
|
||||
{
|
||||
idLength = 4; // size of int
|
||||
clockLength = 8; // size of long
|
||||
countLength = 8; // size of long
|
||||
|
||||
stepLength = idLength + clockLength + countLength;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreate() throws UnknownHostException
|
||||
{
|
||||
AbstractCommutativeType type = CounterColumnType.instance;
|
||||
long delta = 3L;
|
||||
CounterColumn column = (CounterColumn)type.createColumn(ByteBufferUtil.bytes("x"), FBUtilities.toByteBuffer(delta), 1L);
|
||||
assert delta == column.value().getLong(column.value().arrayOffset());
|
||||
assert 0 == column.partitionedCounter().length;
|
||||
|
||||
InetAddress node = InetAddress.getByAddress(FBUtilities.toByteArray(1));
|
||||
column.update(node);
|
||||
assert delta == column.value().getLong(column.value().arrayOffset());
|
||||
assert 1 == FBUtilities.byteArrayToInt( column.partitionedCounter(), 0*stepLength);
|
||||
assert 1L == FBUtilities.byteArrayToLong(column.partitionedCounter(), 0*stepLength + idLength);
|
||||
assert 3L == FBUtilities.byteArrayToLong(column.partitionedCounter(), 0*stepLength + idLength + clockLength);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdate() throws UnknownHostException
|
||||
{
|
||||
CounterColumn c = new CounterColumn(ByteBufferUtil.bytes("x"), FBUtilities.toByteBuffer(0L), 0L);
|
||||
assert 0L == c.value().getLong(c.value().arrayOffset());
|
||||
|
||||
assert c.partitionedCounter().length == 0 : "badly formatted initial context";
|
||||
|
||||
c.value = FBUtilities.toByteBuffer(1L);
|
||||
c.update(InetAddress.getByAddress(FBUtilities.toByteArray(1)));
|
||||
assert 1L == c.value().getLong(c.value().arrayOffset());
|
||||
|
||||
assert c.partitionedCounter().length == stepLength;
|
||||
|
||||
assert 1 == FBUtilities.byteArrayToInt( c.partitionedCounter(), 0*stepLength);
|
||||
assert 1L == FBUtilities.byteArrayToLong(c.partitionedCounter(), 0*stepLength + idLength);
|
||||
assert 1L == FBUtilities.byteArrayToLong(c.partitionedCounter(), 0*stepLength + idLength + clockLength);
|
||||
|
||||
c.value = FBUtilities.toByteBuffer(3L);
|
||||
c.update(InetAddress.getByAddress(FBUtilities.toByteArray(2)));
|
||||
|
||||
c.value = FBUtilities.toByteBuffer(2L);
|
||||
c.update(InetAddress.getByAddress(FBUtilities.toByteArray(2)));
|
||||
|
||||
c.value = FBUtilities.toByteBuffer(9L);
|
||||
c.update(InetAddress.getByAddress(FBUtilities.toByteArray(2)));
|
||||
|
||||
assert 15L == c.value().getLong(c.value().arrayOffset());
|
||||
|
||||
assert c.partitionedCounter().length == (2 * stepLength);
|
||||
|
||||
assert 2 == FBUtilities.byteArrayToInt(c.partitionedCounter(), 0*stepLength);
|
||||
assert 3L == FBUtilities.byteArrayToLong(c.partitionedCounter(), 0*stepLength + idLength);
|
||||
assert 14L == FBUtilities.byteArrayToLong(c.partitionedCounter(), 0*stepLength + idLength + clockLength);
|
||||
|
||||
assert 1 == FBUtilities.byteArrayToInt(c.partitionedCounter(), 1*stepLength);
|
||||
assert 1L == FBUtilities.byteArrayToLong(c.partitionedCounter(), 1*stepLength + idLength);
|
||||
assert 1L == FBUtilities.byteArrayToLong(c.partitionedCounter(), 1*stepLength + idLength + clockLength);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReconcile() throws UnknownHostException
|
||||
{
|
||||
IColumn left;
|
||||
IColumn right;
|
||||
IColumn reconciled;
|
||||
|
||||
// tombstone + tombstone
|
||||
left = new DeletedColumn(ByteBufferUtil.bytes("x"), 1, 1L);
|
||||
right = new DeletedColumn(ByteBufferUtil.bytes("x"), 2, 2L);
|
||||
|
||||
assert left.reconcile(right).timestamp() == right.timestamp();
|
||||
assert right.reconcile(left).timestamp() == right.timestamp();
|
||||
|
||||
// tombstone > live
|
||||
left = new DeletedColumn(ByteBufferUtil.bytes("x"), 1, 2L);
|
||||
right = new CounterColumn(ByteBufferUtil.bytes("x"), FBUtilities.toByteBuffer(0L), 1L);
|
||||
|
||||
assert left.reconcile(right) == left;
|
||||
|
||||
// tombstone < live last delete
|
||||
left = new DeletedColumn(ByteBufferUtil.bytes("x"), 1, 1L);
|
||||
right = new CounterColumn(ByteBufferUtil.bytes("x"), FBUtilities.toByteBuffer(0L), 4L, new byte[0], 2L);
|
||||
|
||||
assert left.reconcile(right) == right;
|
||||
|
||||
// tombstone == live last delete
|
||||
left = new DeletedColumn(ByteBufferUtil.bytes("x"), 1, 2L);
|
||||
right = new CounterColumn(ByteBufferUtil.bytes("x"), FBUtilities.toByteBuffer(0L), 4L, new byte[0], 2L);
|
||||
|
||||
assert left.reconcile(right) == right;
|
||||
|
||||
// tombstone > live last delete
|
||||
left = new DeletedColumn(ByteBufferUtil.bytes("x"), 1, 4L);
|
||||
right = new CounterColumn(ByteBufferUtil.bytes("x"), FBUtilities.toByteBuffer(0L), 9L, new byte[0], 1L);
|
||||
|
||||
reconciled = left.reconcile(right);
|
||||
assert reconciled.name() == right.name();
|
||||
assert reconciled.value() == right.value();
|
||||
assert reconciled.timestamp() == right.timestamp();
|
||||
assert ((CounterColumn)reconciled).partitionedCounter() == ((CounterColumn)right).partitionedCounter();
|
||||
assert ((CounterColumn)reconciled).timestampOfLastDelete() == left.timestamp();
|
||||
|
||||
// live < tombstone
|
||||
left = new CounterColumn(ByteBufferUtil.bytes("x"), FBUtilities.toByteBuffer(0L), 1L);
|
||||
right = new DeletedColumn(ByteBufferUtil.bytes("x"), 1, 2L);
|
||||
|
||||
assert left.reconcile(right) == right;
|
||||
|
||||
// live last delete > tombstone
|
||||
left = new CounterColumn(ByteBufferUtil.bytes("x"), FBUtilities.toByteBuffer(0L), 4L, new byte[0], 2L);
|
||||
right = new DeletedColumn(ByteBufferUtil.bytes("x"), 1, 1L);
|
||||
|
||||
assert left.reconcile(right) == left;
|
||||
|
||||
// live last delete == tombstone
|
||||
left = new CounterColumn(ByteBufferUtil.bytes("x"), FBUtilities.toByteBuffer(0L), 4L, new byte[0], 2L);
|
||||
right = new DeletedColumn(ByteBufferUtil.bytes("x"), 1, 2L);
|
||||
|
||||
assert left.reconcile(right) == left;
|
||||
|
||||
// live last delete < tombstone
|
||||
left = new CounterColumn(ByteBufferUtil.bytes("x"), FBUtilities.toByteBuffer(0L), 9L, new byte[0], 1L);
|
||||
right = new DeletedColumn(ByteBufferUtil.bytes("x"), 1, 4L);
|
||||
|
||||
reconciled = left.reconcile(right);
|
||||
assert reconciled.name() == left.name();
|
||||
assert reconciled.value() == left.value();
|
||||
assert reconciled.timestamp() == left.timestamp();
|
||||
assert ((CounterColumn)reconciled).partitionedCounter() == ((CounterColumn)left).partitionedCounter();
|
||||
assert ((CounterColumn)reconciled).timestampOfLastDelete() == right.timestamp();
|
||||
|
||||
// live + live
|
||||
byte[] context;
|
||||
|
||||
context = new byte[0];
|
||||
context = cc.update(context, InetAddress.getByAddress(FBUtilities.toByteArray(1)), 1L);
|
||||
context = cc.update(context, InetAddress.getByAddress(FBUtilities.toByteArray(1)), 0L);
|
||||
context = cc.update(context, InetAddress.getByAddress(FBUtilities.toByteArray(1)), 1L);
|
||||
context = cc.update(context, InetAddress.getByAddress(FBUtilities.toByteArray(2)), 0L);
|
||||
context = cc.update(context, InetAddress.getByAddress(FBUtilities.toByteArray(2)), 5L);
|
||||
left = new CounterColumn(ByteBufferUtil.bytes("x"), ByteBuffer.wrap(cc.total(context)), 9L, context, 1L);
|
||||
|
||||
context = new byte[0];
|
||||
context = cc.update(context, InetAddress.getByAddress(FBUtilities.toByteArray(2)), 4L);
|
||||
context = cc.update(context, InetAddress.getByAddress(FBUtilities.toByteArray(3)), 2L);
|
||||
right = new CounterColumn(ByteBufferUtil.bytes("x"), ByteBuffer.wrap(cc.total(context)), 3L, context, 4L);
|
||||
|
||||
reconciled = left.reconcile(right);
|
||||
assert reconciled.name() == left.name();
|
||||
assert 9L == reconciled.value().getLong(reconciled.value().arrayOffset());
|
||||
assert reconciled.timestamp() == 9L;
|
||||
|
||||
context = ((CounterColumn)reconciled).partitionedCounter();
|
||||
assert 3 * stepLength == context.length;
|
||||
|
||||
assert 1 == FBUtilities.byteArrayToInt(context, 0*stepLength);
|
||||
assert 3L == FBUtilities.byteArrayToLong(context, 0*stepLength + idLength);
|
||||
assert 2L == FBUtilities.byteArrayToLong(context, 0*stepLength + idLength + clockLength);
|
||||
|
||||
assert 2 == FBUtilities.byteArrayToInt(context, 1*stepLength);
|
||||
assert 2L == FBUtilities.byteArrayToLong(context, 1*stepLength + idLength);
|
||||
assert 5L == FBUtilities.byteArrayToLong(context, 1*stepLength + idLength + clockLength);
|
||||
|
||||
assert 3 == FBUtilities.byteArrayToInt(context, 2*stepLength);
|
||||
assert 1L == FBUtilities.byteArrayToLong(context, 2*stepLength + idLength);
|
||||
assert 2L == FBUtilities.byteArrayToLong(context, 2*stepLength + idLength + clockLength);
|
||||
|
||||
assert ((CounterColumn)reconciled).timestampOfLastDelete() == 4L;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDiff() throws UnknownHostException
|
||||
{
|
||||
byte[] left;
|
||||
byte[] right;
|
||||
|
||||
CounterColumn leftCol;
|
||||
CounterColumn rightCol;
|
||||
|
||||
// timestamp
|
||||
left = new byte[0];
|
||||
leftCol = new CounterColumn(ByteBufferUtil.bytes("x"), ByteBuffer.wrap(cc.total(left)), 1L, left);
|
||||
|
||||
right = new byte[0];
|
||||
rightCol = new CounterColumn(ByteBufferUtil.bytes("x"), ByteBuffer.wrap(cc.total(right)), 2L, right);
|
||||
|
||||
assert rightCol == leftCol.diff(rightCol);
|
||||
assert null == rightCol.diff(leftCol);
|
||||
|
||||
// timestampOfLastDelete
|
||||
left = new byte[0];
|
||||
leftCol = new CounterColumn(ByteBufferUtil.bytes("x"), ByteBuffer.wrap(cc.total(left)), 1L, left, 1L);
|
||||
|
||||
right = new byte[0];
|
||||
rightCol = new CounterColumn(ByteBufferUtil.bytes("x"), ByteBuffer.wrap(cc.total(right)), 1L, right, 2L);
|
||||
|
||||
assert rightCol == leftCol.diff(rightCol);
|
||||
assert null == rightCol.diff(leftCol);
|
||||
|
||||
// equality: equal nodes, all counts same
|
||||
left = Util.concatByteArrays(
|
||||
FBUtilities.toByteArray(3), FBUtilities.toByteArray(3L), FBUtilities.toByteArray(0L),
|
||||
FBUtilities.toByteArray(6), FBUtilities.toByteArray(2L), FBUtilities.toByteArray(0L),
|
||||
FBUtilities.toByteArray(9), FBUtilities.toByteArray(1L), FBUtilities.toByteArray(0L)
|
||||
);
|
||||
left = cc.update(left, InetAddress.getByAddress(FBUtilities.toByteArray(3)), 0L);
|
||||
right = ArrayUtils.clone(left);
|
||||
|
||||
leftCol = new CounterColumn(ByteBufferUtil.bytes("x"), ByteBuffer.wrap(cc.total(left)), 1L, left);
|
||||
rightCol = new CounterColumn(ByteBufferUtil.bytes("x"), ByteBuffer.wrap(cc.total(right)), 1L, right);
|
||||
assert null == leftCol.diff(rightCol);
|
||||
|
||||
// greater than: left has superset of nodes (counts equal)
|
||||
left = Util.concatByteArrays(
|
||||
FBUtilities.toByteArray(3), FBUtilities.toByteArray(3L), FBUtilities.toByteArray(0L),
|
||||
FBUtilities.toByteArray(6), FBUtilities.toByteArray(2L), FBUtilities.toByteArray(0L),
|
||||
FBUtilities.toByteArray(9), FBUtilities.toByteArray(1L), FBUtilities.toByteArray(0L),
|
||||
FBUtilities.toByteArray(12), FBUtilities.toByteArray(0L), FBUtilities.toByteArray(0L)
|
||||
);
|
||||
right = Util.concatByteArrays(
|
||||
FBUtilities.toByteArray(3), FBUtilities.toByteArray(3L), FBUtilities.toByteArray(0L),
|
||||
FBUtilities.toByteArray(6), FBUtilities.toByteArray(2L), FBUtilities.toByteArray(0L),
|
||||
FBUtilities.toByteArray(9), FBUtilities.toByteArray(1L), FBUtilities.toByteArray(0L)
|
||||
);
|
||||
|
||||
leftCol = new CounterColumn(ByteBufferUtil.bytes("x"), ByteBuffer.wrap(cc.total(left)), 1L, left);
|
||||
rightCol = new CounterColumn(ByteBufferUtil.bytes("x"), ByteBuffer.wrap(cc.total(right)), 1L, right);
|
||||
assert null == leftCol.diff(rightCol);
|
||||
|
||||
// less than: right has subset of nodes (counts equal)
|
||||
assert leftCol == rightCol.diff(leftCol);
|
||||
|
||||
// disjoint: right and left have disjoint node sets
|
||||
left = Util.concatByteArrays(
|
||||
FBUtilities.toByteArray(3), FBUtilities.toByteArray(1L), FBUtilities.toByteArray(0L),
|
||||
FBUtilities.toByteArray(4), FBUtilities.toByteArray(1L), FBUtilities.toByteArray(0L),
|
||||
FBUtilities.toByteArray(9), FBUtilities.toByteArray(1L), FBUtilities.toByteArray(0L)
|
||||
);
|
||||
right = Util.concatByteArrays(
|
||||
FBUtilities.toByteArray(3), FBUtilities.toByteArray(1L), FBUtilities.toByteArray(0L),
|
||||
FBUtilities.toByteArray(6), FBUtilities.toByteArray(1L), FBUtilities.toByteArray(0L),
|
||||
FBUtilities.toByteArray(9), FBUtilities.toByteArray(1L), FBUtilities.toByteArray(0L)
|
||||
);
|
||||
|
||||
leftCol = new CounterColumn(ByteBufferUtil.bytes("x"), ByteBuffer.wrap(cc.total(left)), 1L, left);
|
||||
rightCol = new CounterColumn(ByteBufferUtil.bytes("x"), ByteBuffer.wrap(cc.total(right)), 1L, right);
|
||||
assert rightCol == leftCol.diff(rightCol);
|
||||
assert leftCol == rightCol.diff(leftCol);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCleanNodeCounts() throws UnknownHostException
|
||||
{
|
||||
byte[] context = Util.concatByteArrays(
|
||||
FBUtilities.toByteArray(1), FBUtilities.toByteArray(1L), FBUtilities.toByteArray(1L),
|
||||
FBUtilities.toByteArray(2), FBUtilities.toByteArray(2L), FBUtilities.toByteArray(2L),
|
||||
FBUtilities.toByteArray(4), FBUtilities.toByteArray(3L), FBUtilities.toByteArray(3L),
|
||||
FBUtilities.toByteArray(8), FBUtilities.toByteArray(4L), FBUtilities.toByteArray(4L)
|
||||
);
|
||||
CounterColumn c = new CounterColumn(ByteBufferUtil.bytes("x"), ByteBuffer.wrap(cc.total(context)), 1L, context);
|
||||
|
||||
CounterColumn d = c.cleanNodeCounts(InetAddress.getByAddress(FBUtilities.toByteArray(4)));
|
||||
|
||||
assertEquals(7L, d.value().getLong(d.value().arrayOffset()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerializeDeserialize() throws IOException
|
||||
{
|
||||
ColumnFamily cf;
|
||||
|
||||
byte[] context = Util.concatByteArrays(
|
||||
FBUtilities.toByteArray(1), FBUtilities.toByteArray(1L), FBUtilities.toByteArray(1L),
|
||||
FBUtilities.toByteArray(2), FBUtilities.toByteArray(2L), FBUtilities.toByteArray(2L),
|
||||
FBUtilities.toByteArray(4), FBUtilities.toByteArray(3L), FBUtilities.toByteArray(3L),
|
||||
FBUtilities.toByteArray(8), FBUtilities.toByteArray(4L), FBUtilities.toByteArray(4L)
|
||||
);
|
||||
CounterColumn original = new CounterColumn(ByteBufferUtil.bytes("x"), ByteBuffer.wrap(cc.total(context)), 1L, context);
|
||||
|
||||
DataOutputBuffer bufOut = new DataOutputBuffer();
|
||||
Column.serializer().serialize(original, bufOut);
|
||||
|
||||
ByteArrayInputStream bufIn = new ByteArrayInputStream(bufOut.getData(), 0, bufOut.getLength());
|
||||
CounterColumn deserialized = (CounterColumn)Column.serializer().deserialize(new DataInputStream(bufIn));
|
||||
|
||||
assert original.equals(deserialized);
|
||||
}
|
||||
}
|
||||
|
|
@ -115,6 +115,7 @@ public class DefsTest extends CleanupHelper
|
|||
1.0,
|
||||
1.0,
|
||||
0.5,
|
||||
false,
|
||||
100000,
|
||||
null,
|
||||
500,
|
||||
|
|
@ -766,6 +767,7 @@ public class DefsTest extends CleanupHelper
|
|||
0,
|
||||
1.0,
|
||||
0,
|
||||
false,
|
||||
CFMetaData.DEFAULT_GC_GRACE_SECONDS,
|
||||
BytesType.instance,
|
||||
CFMetaData.DEFAULT_MIN_COMPACTION_THRESHOLD,
|
||||
|
|
|
|||
|
|
@ -24,12 +24,16 @@ import org.junit.Test;
|
|||
import static junit.framework.Assert.assertNotNull;
|
||||
import static junit.framework.Assert.assertNull;
|
||||
import static org.apache.cassandra.Util.getBytes;
|
||||
import static org.apache.cassandra.Util.concatByteArrays;
|
||||
import org.apache.cassandra.db.context.CounterContext;
|
||||
import org.apache.cassandra.db.marshal.LongType;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
||||
public class SuperColumnTest
|
||||
{
|
||||
private static final CounterContext cc = new CounterContext();
|
||||
|
||||
@Test
|
||||
public void testMissingSubcolumn() {
|
||||
SuperColumn sc = new SuperColumn(ByteBufferUtil.bytes("sc1"), LongType.instance);
|
||||
|
|
@ -37,4 +41,69 @@ public class SuperColumnTest
|
|||
assertNotNull(sc.getSubColumn(getBytes(1)));
|
||||
assertNull(sc.getSubColumn(getBytes(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddColumnIncrementCounter()
|
||||
{
|
||||
byte[] context;
|
||||
|
||||
SuperColumn sc = new SuperColumn(ByteBufferUtil.bytes("sc1"), LongType.instance);
|
||||
|
||||
context = concatByteArrays(
|
||||
FBUtilities.getLocalAddress().getAddress(), FBUtilities.toByteArray(3L), FBUtilities.toByteArray(3L),
|
||||
FBUtilities.toByteArray(1), FBUtilities.toByteArray(7L), FBUtilities.toByteArray(0L),
|
||||
FBUtilities.toByteArray(2), FBUtilities.toByteArray(5L), FBUtilities.toByteArray(7L),
|
||||
FBUtilities.toByteArray(4), FBUtilities.toByteArray(2L), FBUtilities.toByteArray(9L)
|
||||
);
|
||||
sc.addColumn(new CounterColumn(getBytes(1), ByteBuffer.wrap(cc.total(context)), 3L, context, 0L));
|
||||
context = concatByteArrays(
|
||||
FBUtilities.getLocalAddress().getAddress(), FBUtilities.toByteArray(9L), FBUtilities.toByteArray(5L),
|
||||
FBUtilities.toByteArray(8), FBUtilities.toByteArray(9L), FBUtilities.toByteArray(0L),
|
||||
FBUtilities.toByteArray(4), FBUtilities.toByteArray(4L), FBUtilities.toByteArray(1L),
|
||||
FBUtilities.toByteArray(2), FBUtilities.toByteArray(3L), FBUtilities.toByteArray(4L)
|
||||
);
|
||||
sc.addColumn(new CounterColumn(getBytes(1), ByteBuffer.wrap(cc.total(context)), 10L, context, 0L));
|
||||
|
||||
context = concatByteArrays(
|
||||
FBUtilities.toByteArray(3), FBUtilities.toByteArray(6L), FBUtilities.toByteArray(0L),
|
||||
FBUtilities.toByteArray(7), FBUtilities.toByteArray(3L), FBUtilities.toByteArray(0L),
|
||||
FBUtilities.toByteArray(2), FBUtilities.toByteArray(1L), FBUtilities.toByteArray(0L)
|
||||
);
|
||||
sc.addColumn(new CounterColumn(getBytes(2), ByteBuffer.wrap(cc.total(context)), 9L, context, 0L));
|
||||
|
||||
assertNotNull(sc.getSubColumn(getBytes(1)));
|
||||
assertNull(sc.getSubColumn(getBytes(3)));
|
||||
|
||||
// column: 1
|
||||
byte[] c1 = concatByteArrays(
|
||||
FBUtilities.getLocalAddress().getAddress(), FBUtilities.toByteArray(12L), FBUtilities.toByteArray(8L),
|
||||
FBUtilities.toByteArray(8), FBUtilities.toByteArray(9L), FBUtilities.toByteArray(0L),
|
||||
FBUtilities.toByteArray(1), FBUtilities.toByteArray(7L), FBUtilities.toByteArray(0L),
|
||||
FBUtilities.toByteArray(2), FBUtilities.toByteArray(5L), FBUtilities.toByteArray(7L),
|
||||
FBUtilities.toByteArray(4), FBUtilities.toByteArray(4L), FBUtilities.toByteArray(1L)
|
||||
);
|
||||
assert 0 == FBUtilities.compareByteSubArrays(
|
||||
((CounterColumn)sc.getSubColumn(getBytes(1))).partitionedCounter(),
|
||||
0,
|
||||
c1,
|
||||
0,
|
||||
c1.length);
|
||||
|
||||
// column: 2
|
||||
byte[] c2 = concatByteArrays(
|
||||
FBUtilities.toByteArray(3), FBUtilities.toByteArray(6L), FBUtilities.toByteArray(0L),
|
||||
FBUtilities.toByteArray(7), FBUtilities.toByteArray(3L), FBUtilities.toByteArray(0L),
|
||||
FBUtilities.toByteArray(2), FBUtilities.toByteArray(1L), FBUtilities.toByteArray(0L)
|
||||
);
|
||||
assert 0 == FBUtilities.compareByteSubArrays(
|
||||
((CounterColumn)sc.getSubColumn(getBytes(2))).partitionedCounter(),
|
||||
0,
|
||||
c2,
|
||||
0,
|
||||
c2.length);
|
||||
|
||||
assertNotNull(sc.getSubColumn(getBytes(1)));
|
||||
assertNotNull(sc.getSubColumn(getBytes(2)));
|
||||
assertNull(sc.getSubColumn(getBytes(3)));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,536 @@
|
|||
/*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
package org.apache.cassandra.db.context;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.cassandra.Util;
|
||||
import org.apache.cassandra.db.context.IContext.ContextRelationship;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
||||
/**
|
||||
* Note: these tests assume IPv4 (4 bytes) is used for id.
|
||||
* if IPv6 (16 bytes) is used, tests will fail (but the code will work).
|
||||
* however, it might be pragmatic to modify the code to just use
|
||||
* the IPv4 portion of the IPv6 address-space.
|
||||
*/
|
||||
public class CounterContextTest
|
||||
{
|
||||
private static final CounterContext cc = new CounterContext();
|
||||
|
||||
private static final InetAddress idAddress;
|
||||
private static final byte[] id;
|
||||
private static final int idLength;
|
||||
private static final int clockLength;
|
||||
private static final int countLength;
|
||||
|
||||
private static final int stepLength;
|
||||
private static final int defaultEntries;
|
||||
|
||||
static
|
||||
{
|
||||
idAddress = FBUtilities.getLocalAddress();
|
||||
id = idAddress.getAddress();
|
||||
idLength = 4; // size of int
|
||||
clockLength = 8; // size of long
|
||||
countLength = 8; // size of long
|
||||
stepLength = idLength + clockLength + countLength;
|
||||
|
||||
defaultEntries = 10;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreate()
|
||||
{
|
||||
byte[] context = cc.create();
|
||||
assert context.length == 0;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdatePresentReorder() throws UnknownHostException
|
||||
{
|
||||
byte[] context;
|
||||
|
||||
context = new byte[stepLength * defaultEntries];
|
||||
|
||||
for (int i = 0; i < defaultEntries - 1; i++)
|
||||
{
|
||||
cc.writeElementAtStepOffset(
|
||||
context,
|
||||
i,
|
||||
FBUtilities.toByteArray(i),
|
||||
1L,
|
||||
1L);
|
||||
}
|
||||
cc.writeElementAtStepOffset(
|
||||
context,
|
||||
(defaultEntries - 1),
|
||||
id,
|
||||
2L,
|
||||
3L);
|
||||
|
||||
context = cc.update(context, idAddress, 10L);
|
||||
|
||||
assertEquals(context.length, stepLength * defaultEntries);
|
||||
assertEquals( 3L, FBUtilities.byteArrayToLong(context, idLength));
|
||||
assertEquals( 13L, FBUtilities.byteArrayToLong(context, idLength + clockLength));
|
||||
for (int i = 1; i < defaultEntries; i++)
|
||||
{
|
||||
int offset = i * stepLength;
|
||||
assertEquals( i-1, FBUtilities.byteArrayToInt(context, offset));
|
||||
assertEquals(1L, FBUtilities.byteArrayToLong(context, offset + idLength));
|
||||
assertEquals(1L, FBUtilities.byteArrayToLong(context, offset + idLength + clockLength));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateNotPresent()
|
||||
{
|
||||
byte[] context = new byte[stepLength * 2];
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
cc.writeElementAtStepOffset(
|
||||
context,
|
||||
i,
|
||||
FBUtilities.toByteArray(i),
|
||||
1L,
|
||||
1L);
|
||||
}
|
||||
|
||||
context = cc.update(context, idAddress, 328L);
|
||||
|
||||
assert context.length == stepLength * 3;
|
||||
assert 1L == FBUtilities.byteArrayToLong(context, idLength);
|
||||
assert 328L == FBUtilities.byteArrayToLong(context, idLength + clockLength);
|
||||
for (int i = 1; i < 3; i++)
|
||||
{
|
||||
int offset = i * stepLength;
|
||||
assert i-1 == FBUtilities.byteArrayToInt(context, offset);
|
||||
assert 1L == FBUtilities.byteArrayToLong(context, offset + idLength);
|
||||
assert 1L == FBUtilities.byteArrayToLong(context, offset + idLength + clockLength);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwapElement()
|
||||
{
|
||||
byte[] context = new byte[stepLength * 3];
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
cc.writeElementAtStepOffset(
|
||||
context,
|
||||
i,
|
||||
FBUtilities.toByteArray(i),
|
||||
1L,
|
||||
1L);
|
||||
}
|
||||
cc.swapElement(context, 0, 2*stepLength);
|
||||
|
||||
assert 2 == FBUtilities.byteArrayToInt(context, 0);
|
||||
assert 0 == FBUtilities.byteArrayToInt(context, 2*stepLength);
|
||||
|
||||
cc.swapElement(context, 0, 1*stepLength);
|
||||
|
||||
assert 1 == FBUtilities.byteArrayToInt(context, 0);
|
||||
assert 2 == FBUtilities.byteArrayToInt(context, 1*stepLength);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPartitionElements()
|
||||
{
|
||||
byte[] context = new byte[stepLength * 10];
|
||||
|
||||
cc.writeElementAtStepOffset(context, 0, FBUtilities.toByteArray(5), 1L, 1L);
|
||||
cc.writeElementAtStepOffset(context, 1, FBUtilities.toByteArray(3), 1L, 1L);
|
||||
cc.writeElementAtStepOffset(context, 2, FBUtilities.toByteArray(6), 1L, 1L);
|
||||
cc.writeElementAtStepOffset(context, 3, FBUtilities.toByteArray(7), 1L, 1L);
|
||||
cc.writeElementAtStepOffset(context, 4, FBUtilities.toByteArray(8), 1L, 1L);
|
||||
cc.writeElementAtStepOffset(context, 5, FBUtilities.toByteArray(9), 1L, 1L);
|
||||
cc.writeElementAtStepOffset(context, 6, FBUtilities.toByteArray(2), 1L, 1L);
|
||||
cc.writeElementAtStepOffset(context, 7, FBUtilities.toByteArray(4), 1L, 1L);
|
||||
cc.writeElementAtStepOffset(context, 8, FBUtilities.toByteArray(1), 1L, 1L);
|
||||
cc.writeElementAtStepOffset(context, 9, FBUtilities.toByteArray(3), 1L, 1L);
|
||||
|
||||
cc.partitionElements(
|
||||
context,
|
||||
0, // left
|
||||
9, // right (inclusive)
|
||||
2 // pivot
|
||||
);
|
||||
|
||||
assert 5 == FBUtilities.byteArrayToInt(context, 0*stepLength);
|
||||
assert 3 == FBUtilities.byteArrayToInt(context, 1*stepLength);
|
||||
assert 3 == FBUtilities.byteArrayToInt(context, 2*stepLength);
|
||||
assert 2 == FBUtilities.byteArrayToInt(context, 3*stepLength);
|
||||
assert 4 == FBUtilities.byteArrayToInt(context, 4*stepLength);
|
||||
assert 1 == FBUtilities.byteArrayToInt(context, 5*stepLength);
|
||||
assert 6 == FBUtilities.byteArrayToInt(context, 6*stepLength);
|
||||
assert 8 == FBUtilities.byteArrayToInt(context, 7*stepLength);
|
||||
assert 9 == FBUtilities.byteArrayToInt(context, 8*stepLength);
|
||||
assert 7 == FBUtilities.byteArrayToInt(context, 9*stepLength);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSortElementsById()
|
||||
{
|
||||
byte[] context = new byte[stepLength * 10];
|
||||
|
||||
cc.writeElementAtStepOffset(context, 0, FBUtilities.toByteArray(5), 1L, 1L);
|
||||
cc.writeElementAtStepOffset(context, 1, FBUtilities.toByteArray(3), 1L, 1L);
|
||||
cc.writeElementAtStepOffset(context, 2, FBUtilities.toByteArray(6), 1L, 1L);
|
||||
cc.writeElementAtStepOffset(context, 3, FBUtilities.toByteArray(7), 1L, 1L);
|
||||
cc.writeElementAtStepOffset(context, 4, FBUtilities.toByteArray(8), 1L, 1L);
|
||||
cc.writeElementAtStepOffset(context, 5, FBUtilities.toByteArray(9), 1L, 1L);
|
||||
cc.writeElementAtStepOffset(context, 6, FBUtilities.toByteArray(2), 1L, 1L);
|
||||
cc.writeElementAtStepOffset(context, 7, FBUtilities.toByteArray(4), 1L, 1L);
|
||||
cc.writeElementAtStepOffset(context, 8, FBUtilities.toByteArray(1), 1L, 1L);
|
||||
cc.writeElementAtStepOffset(context, 9, FBUtilities.toByteArray(3), 1L, 1L);
|
||||
|
||||
byte[] sorted = cc.sortElementsById(context);
|
||||
|
||||
assertEquals( 1, FBUtilities.byteArrayToInt(sorted, 0*stepLength));
|
||||
assertEquals( 2, FBUtilities.byteArrayToInt(sorted, 1*stepLength));
|
||||
assertEquals( 3, FBUtilities.byteArrayToInt(sorted, 2*stepLength));
|
||||
assertEquals( 3, FBUtilities.byteArrayToInt(sorted, 3*stepLength));
|
||||
assertEquals( 4, FBUtilities.byteArrayToInt(sorted, 4*stepLength));
|
||||
assertEquals( 5, FBUtilities.byteArrayToInt(sorted, 5*stepLength));
|
||||
assertEquals( 6, FBUtilities.byteArrayToInt(sorted, 6*stepLength));
|
||||
assertEquals( 7, FBUtilities.byteArrayToInt(sorted, 7*stepLength));
|
||||
assertEquals( 8, FBUtilities.byteArrayToInt(sorted, 8*stepLength));
|
||||
assertEquals( 9, FBUtilities.byteArrayToInt(sorted, 9*stepLength));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDiff()
|
||||
{
|
||||
byte[] left = new byte[3 * stepLength];
|
||||
byte[] right;
|
||||
|
||||
// equality: equal nodes, all counts same
|
||||
cc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 3L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(6), 2L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 1L, 0L);
|
||||
right = ArrayUtils.clone(left);
|
||||
|
||||
assert ContextRelationship.EQUAL ==
|
||||
cc.diff(left, right);
|
||||
|
||||
// greater than: left has superset of nodes (counts equal)
|
||||
left = new byte[4 * stepLength];
|
||||
cc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 3L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(6), 2L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 1L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 3, FBUtilities.toByteArray(12), 0L, 0L);
|
||||
|
||||
right = new byte[3 * stepLength];
|
||||
cc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(3), 3L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 2L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(9), 1L, 0L);
|
||||
|
||||
assert ContextRelationship.GREATER_THAN ==
|
||||
cc.diff(left, right);
|
||||
|
||||
// less than: left has subset of nodes (counts equal)
|
||||
left = new byte[3 * stepLength];
|
||||
cc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 3L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(6), 2L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 1L, 0L);
|
||||
|
||||
right = new byte[4 * stepLength];
|
||||
cc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(3), 3L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 2L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(9), 1L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 3, FBUtilities.toByteArray(12), 0L, 0L);
|
||||
|
||||
assert ContextRelationship.LESS_THAN ==
|
||||
cc.diff(left, right);
|
||||
|
||||
// greater than: equal nodes, but left has higher counts
|
||||
left = new byte[3 * stepLength];
|
||||
cc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 3L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(6), 2L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 3L, 0L);
|
||||
|
||||
right = new byte[3 * stepLength];
|
||||
cc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(3), 3L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 2L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(9), 1L, 0L);
|
||||
|
||||
assert ContextRelationship.GREATER_THAN ==
|
||||
cc.diff(left, right);
|
||||
|
||||
// less than: equal nodes, but right has higher counts
|
||||
left = new byte[3 * stepLength];
|
||||
cc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 3L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(6), 2L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 3L, 0L);
|
||||
|
||||
right = new byte[3 * stepLength];
|
||||
cc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(3), 3L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 9L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(9), 3L, 0L);
|
||||
|
||||
assert ContextRelationship.LESS_THAN ==
|
||||
cc.diff(left, right);
|
||||
|
||||
// disjoint: right and left have disjoint node sets
|
||||
left = new byte[3 * stepLength];
|
||||
cc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 1L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(4), 1L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 1L, 0L);
|
||||
|
||||
right = new byte[3 * stepLength];
|
||||
cc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(3), 1L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 1L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(9), 1L, 0L);
|
||||
|
||||
assert ContextRelationship.DISJOINT ==
|
||||
cc.diff(left, right);
|
||||
|
||||
left = new byte[3 * stepLength];
|
||||
cc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 1L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(4), 1L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 1L, 0L);
|
||||
|
||||
right = new byte[3 * stepLength];
|
||||
cc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(2), 1L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 1L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(12), 1L, 0L);
|
||||
|
||||
assert ContextRelationship.DISJOINT ==
|
||||
cc.diff(left, right);
|
||||
|
||||
// disjoint: equal nodes, but right and left have higher counts in differing nodes
|
||||
left = new byte[3 * stepLength];
|
||||
cc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 1L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(6), 3L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 1L, 0L);
|
||||
|
||||
right = new byte[3 * stepLength];
|
||||
cc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(3), 1L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 1L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(9), 5L, 0L);
|
||||
|
||||
assert ContextRelationship.DISJOINT ==
|
||||
cc.diff(left, right);
|
||||
|
||||
left = new byte[3 * stepLength];
|
||||
cc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 2L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(6), 3L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 1L, 0L);
|
||||
|
||||
right = new byte[3 * stepLength];
|
||||
cc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(3), 1L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 9L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(9), 5L, 0L);
|
||||
|
||||
assert ContextRelationship.DISJOINT ==
|
||||
cc.diff(left, right);
|
||||
|
||||
// disjoint: left has more nodes, but lower counts
|
||||
left = new byte[4 * stepLength];
|
||||
cc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 2L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(6), 3L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 1L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 3, FBUtilities.toByteArray(12), 1L, 0L);
|
||||
|
||||
right = new byte[3 * stepLength];
|
||||
cc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(3), 4L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 9L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(9), 5L, 0L);
|
||||
|
||||
assert ContextRelationship.DISJOINT ==
|
||||
cc.diff(left, right);
|
||||
|
||||
// disjoint: left has less nodes, but higher counts
|
||||
left = new byte[3 * stepLength];
|
||||
cc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 5L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(6), 3L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 2L, 0L);
|
||||
|
||||
right = new byte[4 * stepLength];
|
||||
cc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(3), 4L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 3L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(9), 2L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 3, FBUtilities.toByteArray(12), 1L, 0L);
|
||||
|
||||
assert ContextRelationship.DISJOINT ==
|
||||
cc.diff(left, right);
|
||||
|
||||
// disjoint: mixed nodes and counts
|
||||
left = new byte[3 * stepLength];
|
||||
cc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 5L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(6), 2L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 2L, 0L);
|
||||
|
||||
right = new byte[4 * stepLength];
|
||||
cc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(3), 4L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 3L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(9), 2L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 3, FBUtilities.toByteArray(12), 1L, 0L);
|
||||
|
||||
assert ContextRelationship.DISJOINT ==
|
||||
cc.diff(left, right);
|
||||
|
||||
left = new byte[4 * stepLength];
|
||||
cc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 5L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(6), 2L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(7), 2L, 0L);
|
||||
cc.writeElementAtStepOffset(left, 3, FBUtilities.toByteArray(9), 2L, 0L);
|
||||
|
||||
right = new byte[3 * stepLength];
|
||||
cc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(3), 4L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 3L, 0L);
|
||||
cc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(9), 2L, 0L);
|
||||
|
||||
assert ContextRelationship.DISJOINT ==
|
||||
cc.diff(left, right);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMerge()
|
||||
{
|
||||
// note: local counts aggregated; remote counts are reconciled (i.e. take max)
|
||||
byte[] left = new byte[4 * stepLength];
|
||||
cc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(1), 1L, 1L);
|
||||
cc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(2), 2L, 2L);
|
||||
cc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(4), 6L, 3L);
|
||||
cc.writeElementAtStepOffset(
|
||||
left,
|
||||
3,
|
||||
FBUtilities.getLocalAddress().getAddress(),
|
||||
7L,
|
||||
3L);
|
||||
|
||||
byte[] right = new byte[3 * stepLength];
|
||||
cc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(5), 5L, 5L);
|
||||
cc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(4), 4L, 4L);
|
||||
cc.writeElementAtStepOffset(
|
||||
right,
|
||||
0,
|
||||
FBUtilities.getLocalAddress().getAddress(),
|
||||
2L,
|
||||
9L);
|
||||
|
||||
byte[] merged = cc.merge(left, right);
|
||||
|
||||
// local node id's counts are aggregated
|
||||
assertEquals(0, FBUtilities.compareUnsigned(
|
||||
FBUtilities.getLocalAddress().getAddress(),
|
||||
merged,
|
||||
0,
|
||||
0*stepLength,
|
||||
4,
|
||||
4));
|
||||
assertEquals( 9L, FBUtilities.byteArrayToLong(merged, 0*stepLength + idLength));
|
||||
assertEquals(12L, FBUtilities.byteArrayToLong(merged, 0*stepLength + idLength + clockLength));
|
||||
|
||||
// remote node id counts are reconciled (i.e. take max)
|
||||
assertEquals( 4, FBUtilities.byteArrayToInt(merged, 1*stepLength));
|
||||
assertEquals( 6L, FBUtilities.byteArrayToLong(merged, 1*stepLength + idLength));
|
||||
assertEquals( 3L, FBUtilities.byteArrayToLong(merged, 1*stepLength + idLength + clockLength));
|
||||
|
||||
assertEquals( 5, FBUtilities.byteArrayToInt(merged, 2*stepLength));
|
||||
assertEquals( 5L, FBUtilities.byteArrayToLong(merged, 2*stepLength + idLength));
|
||||
assertEquals( 5L, FBUtilities.byteArrayToLong(merged, 2*stepLength + idLength + clockLength));
|
||||
|
||||
assertEquals( 2, FBUtilities.byteArrayToInt(merged, 3*stepLength));
|
||||
assertEquals( 2L, FBUtilities.byteArrayToLong(merged, 3*stepLength + idLength));
|
||||
assertEquals( 2L, FBUtilities.byteArrayToLong(merged, 3*stepLength + idLength + clockLength));
|
||||
|
||||
assertEquals( 1, FBUtilities.byteArrayToInt(merged, 4*stepLength));
|
||||
assertEquals( 1L, FBUtilities.byteArrayToLong(merged, 4*stepLength + idLength));
|
||||
assertEquals( 1L, FBUtilities.byteArrayToLong(merged, 4*stepLength + idLength + clockLength));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTotal()
|
||||
{
|
||||
byte[] left = new byte[4 * stepLength];
|
||||
cc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(1), 1L, 1L);
|
||||
cc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(2), 2L, 2L);
|
||||
cc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(4), 3L, 3L);
|
||||
cc.writeElementAtStepOffset(
|
||||
left,
|
||||
3,
|
||||
FBUtilities.getLocalAddress().getAddress(),
|
||||
3L,
|
||||
3L);
|
||||
|
||||
byte[] right = new byte[3 * stepLength];
|
||||
cc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(5), 5L, 5L);
|
||||
cc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(4), 4L, 4L);
|
||||
cc.writeElementAtStepOffset(
|
||||
right,
|
||||
0,
|
||||
FBUtilities.getLocalAddress().getAddress(),
|
||||
9L,
|
||||
9L);
|
||||
|
||||
byte[] merged = cc.merge(left, right);
|
||||
|
||||
// 127.0.0.1: 12 (3+9)
|
||||
// 0.0.0.1: 1
|
||||
// 0.0.0.2: 2
|
||||
// 0.0.0.4: 4
|
||||
// 0.0.0.5: 5
|
||||
|
||||
assertEquals(24L, FBUtilities.byteArrayToLong(cc.total(merged)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCleanNodeCounts() throws UnknownHostException
|
||||
{
|
||||
byte[] bytes = new byte[4 * stepLength];
|
||||
cc.writeElementAtStepOffset(bytes, 0, FBUtilities.toByteArray(1), 1L, 1L);
|
||||
cc.writeElementAtStepOffset(bytes, 1, FBUtilities.toByteArray(2), 2L, 2L);
|
||||
cc.writeElementAtStepOffset(bytes, 2, FBUtilities.toByteArray(4), 3L, 3L);
|
||||
cc.writeElementAtStepOffset(bytes, 3, FBUtilities.toByteArray(8), 4L, 4L);
|
||||
|
||||
assertEquals(4, FBUtilities.byteArrayToInt(bytes, 2*stepLength));
|
||||
assertEquals(3L, FBUtilities.byteArrayToLong(bytes, 2*stepLength + idLength));
|
||||
|
||||
bytes = cc.cleanNodeCounts(bytes, InetAddress.getByAddress(FBUtilities.toByteArray(4)));
|
||||
|
||||
// node: 0.0.0.4 should be removed
|
||||
assertEquals(3 * stepLength, bytes.length);
|
||||
|
||||
// other nodes should be unaffected
|
||||
assertEquals(1, FBUtilities.byteArrayToInt(bytes, 0*stepLength));
|
||||
assertEquals(1L, FBUtilities.byteArrayToLong(bytes, 0*stepLength + idLength));
|
||||
|
||||
assertEquals(2, FBUtilities.byteArrayToInt(bytes, 1*stepLength));
|
||||
assertEquals(2L, FBUtilities.byteArrayToLong(bytes, 1*stepLength + idLength));
|
||||
|
||||
assertEquals(8, FBUtilities.byteArrayToInt(bytes, 2*stepLength));
|
||||
assertEquals(4L, FBUtilities.byteArrayToLong(bytes, 2*stepLength + idLength));
|
||||
}
|
||||
}
|
||||
|
|
@ -51,6 +51,11 @@ public class SSTableUtils
|
|||
}
|
||||
|
||||
public static File tempSSTableFile(String tablename, String cfname) throws IOException
|
||||
{
|
||||
return tempSSTableFile(tablename, cfname, 0);
|
||||
}
|
||||
|
||||
public static File tempSSTableFile(String tablename, String cfname, int generation) throws IOException
|
||||
{
|
||||
File tempdir = File.createTempFile(tablename, cfname);
|
||||
if(!tempdir.delete() || !tempdir.mkdir())
|
||||
|
|
@ -59,7 +64,7 @@ public class SSTableUtils
|
|||
File tabledir = new File(tempdir, tablename);
|
||||
tabledir.mkdir();
|
||||
tabledir.deleteOnExit();
|
||||
File datafile = new File(new Descriptor(tabledir, tablename, cfname, 0, false).filenameFor("Data.db"));
|
||||
File datafile = new File(new Descriptor(tabledir, tablename, cfname, generation, false).filenameFor("Data.db"));
|
||||
if (!datafile.createNewFile())
|
||||
throw new IOException("unable to create file " + datafile);
|
||||
datafile.deleteOnExit();
|
||||
|
|
@ -92,7 +97,12 @@ public class SSTableUtils
|
|||
|
||||
public static SSTableReader writeRawSSTable(String tablename, String cfname, Map<ByteBuffer, ByteBuffer> entries) throws IOException
|
||||
{
|
||||
File datafile = tempSSTableFile(tablename, cfname);
|
||||
return writeRawSSTable(tablename, cfname, entries, 0);
|
||||
}
|
||||
|
||||
public static SSTableReader writeRawSSTable(String tablename, String cfname, Map<ByteBuffer, ByteBuffer> entries, int generation) throws IOException
|
||||
{
|
||||
File datafile = tempSSTableFile(tablename, cfname, generation);
|
||||
SSTableWriter writer = new SSTableWriter(datafile.getAbsolutePath(), entries.size());
|
||||
SortedMap<DecoratedKey, ByteBuffer> sortedEntries = new TreeMap<DecoratedKey, ByteBuffer>();
|
||||
for (Map.Entry<ByteBuffer, ByteBuffer> entry : entries.entrySet())
|
||||
|
|
|
|||
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
package org.apache.cassandra.io.sstable;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.apache.cassandra.CleanupHelper;
|
||||
import org.apache.cassandra.Util;
|
||||
import org.apache.cassandra.db.*;
|
||||
import org.apache.cassandra.db.context.CounterContext;
|
||||
import org.apache.cassandra.db.marshal.CounterColumnType;
|
||||
import org.apache.cassandra.io.util.BufferedRandomAccessFile;
|
||||
import org.apache.cassandra.io.util.DataOutputBuffer;
|
||||
import org.apache.cassandra.io.util.FileUtils;
|
||||
import org.apache.cassandra.service.StorageService;
|
||||
import org.apache.cassandra.streaming.OperationType;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.junit.Test;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
public class SSTableWriterAESCommutativeTest extends CleanupHelper
|
||||
{
|
||||
private static final CounterContext cc = new CounterContext();
|
||||
private static final CounterColumnType ctype = CounterColumnType.instance;
|
||||
|
||||
@Test
|
||||
public void testRecoverAndOpenAESCommutative() throws IOException, ExecutionException, InterruptedException, UnknownHostException
|
||||
{
|
||||
String keyspace = "Keyspace1";
|
||||
String cfname = "Counter1";
|
||||
|
||||
Map<ByteBuffer, ByteBuffer> entries = new HashMap<ByteBuffer, ByteBuffer>();
|
||||
Map<ByteBuffer, ByteBuffer> cleanedEntries = new HashMap<ByteBuffer, ByteBuffer>();
|
||||
|
||||
DataOutputBuffer buffer;
|
||||
|
||||
ColumnFamily cf = ColumnFamily.create(keyspace, cfname);
|
||||
byte[] context;
|
||||
|
||||
// key: k
|
||||
context = Util.concatByteArrays(
|
||||
FBUtilities.getLocalAddress().getAddress(),
|
||||
FBUtilities.toByteArray(9L),
|
||||
FBUtilities.toByteArray(3L),
|
||||
FBUtilities.toByteArray(2), FBUtilities.toByteArray(4L), FBUtilities.toByteArray(2L),
|
||||
FBUtilities.toByteArray(4), FBUtilities.toByteArray(3L), FBUtilities.toByteArray(3L),
|
||||
FBUtilities.toByteArray(8), FBUtilities.toByteArray(2L), FBUtilities.toByteArray(4L)
|
||||
);
|
||||
cf.addColumn(new CounterColumn(
|
||||
ByteBufferUtil.bytes("x"),
|
||||
ByteBuffer.wrap(cc.total(context)),
|
||||
0L,
|
||||
context
|
||||
));
|
||||
context = Util.concatByteArrays(
|
||||
FBUtilities.toByteArray(1), FBUtilities.toByteArray(7L), FBUtilities.toByteArray(12L),
|
||||
FBUtilities.getLocalAddress().getAddress(),
|
||||
FBUtilities.toByteArray(5L),
|
||||
FBUtilities.toByteArray(3L),
|
||||
FBUtilities.toByteArray(3), FBUtilities.toByteArray(2L), FBUtilities.toByteArray(33L),
|
||||
FBUtilities.toByteArray(9), FBUtilities.toByteArray(1L), FBUtilities.toByteArray(24L)
|
||||
);
|
||||
cf.addColumn(new CounterColumn(
|
||||
ByteBufferUtil.bytes("y"),
|
||||
ByteBuffer.wrap(cc.total(context)),
|
||||
0L,
|
||||
context
|
||||
));
|
||||
|
||||
buffer = new DataOutputBuffer();
|
||||
ColumnFamily.serializer().serializeWithIndexes(cf, buffer);
|
||||
entries.put(
|
||||
ByteBufferUtil.bytes("k"),
|
||||
ByteBuffer.wrap(Arrays.copyOf(buffer.getData(), buffer.getLength()))
|
||||
);
|
||||
|
||||
ctype.cleanContext(cf, FBUtilities.getLocalAddress());
|
||||
buffer = new DataOutputBuffer();
|
||||
ColumnFamily.serializer().serializeWithIndexes(cf, buffer);
|
||||
cleanedEntries.put(
|
||||
ByteBufferUtil.bytes("k"),
|
||||
ByteBuffer.wrap(Arrays.copyOf(buffer.getData(), buffer.getLength()))
|
||||
);
|
||||
|
||||
cf.clear();
|
||||
|
||||
// key: l
|
||||
context = Util.concatByteArrays(
|
||||
FBUtilities.getLocalAddress().getAddress(),
|
||||
FBUtilities.toByteArray(9L),
|
||||
FBUtilities.toByteArray(3L),
|
||||
FBUtilities.toByteArray(2), FBUtilities.toByteArray(4L), FBUtilities.toByteArray(2L),
|
||||
FBUtilities.toByteArray(4), FBUtilities.toByteArray(3L), FBUtilities.toByteArray(3L),
|
||||
FBUtilities.toByteArray(8), FBUtilities.toByteArray(2L), FBUtilities.toByteArray(4L)
|
||||
);
|
||||
cf.addColumn(new CounterColumn(
|
||||
ByteBufferUtil.bytes("x"),
|
||||
ByteBuffer.wrap(cc.total(context)),
|
||||
0L,
|
||||
context
|
||||
));
|
||||
context = Util.concatByteArrays(
|
||||
FBUtilities.toByteArray(1), FBUtilities.toByteArray(7L), FBUtilities.toByteArray(12L),
|
||||
FBUtilities.toByteArray(3), FBUtilities.toByteArray(2L), FBUtilities.toByteArray(33L),
|
||||
FBUtilities.toByteArray(9), FBUtilities.toByteArray(1L), FBUtilities.toByteArray(24L)
|
||||
);
|
||||
cf.addColumn(new CounterColumn(
|
||||
ByteBufferUtil.bytes("y"),
|
||||
ByteBuffer.wrap(cc.total(context)),
|
||||
0L,
|
||||
context
|
||||
));
|
||||
|
||||
buffer = new DataOutputBuffer();
|
||||
ColumnFamily.serializer().serializeWithIndexes(cf, buffer);
|
||||
entries.put(
|
||||
ByteBufferUtil.bytes("l"),
|
||||
ByteBuffer.wrap(Arrays.copyOf(buffer.getData(), buffer.getLength()))
|
||||
);
|
||||
|
||||
ctype.cleanContext(cf, FBUtilities.getLocalAddress());
|
||||
buffer = new DataOutputBuffer();
|
||||
ColumnFamily.serializer().serializeWithIndexes(cf, buffer);
|
||||
cleanedEntries.put(
|
||||
ByteBufferUtil.bytes("l"),
|
||||
ByteBuffer.wrap(Arrays.copyOf(buffer.getData(), buffer.getLength()))
|
||||
);
|
||||
|
||||
cf.clear();
|
||||
|
||||
// write out unmodified CF
|
||||
SSTableReader orig = SSTableUtils.writeRawSSTable(keyspace, cfname, entries, 0);
|
||||
|
||||
// whack the index to trigger the recover
|
||||
FileUtils.deleteWithConfirm(orig.descriptor.filenameFor(Component.PRIMARY_INDEX));
|
||||
FileUtils.deleteWithConfirm(orig.descriptor.filenameFor(Component.FILTER));
|
||||
|
||||
// re-build inline
|
||||
SSTableReader rebuilt = CompactionManager.instance.submitSSTableBuild(
|
||||
orig.descriptor,
|
||||
OperationType.AES
|
||||
).get();
|
||||
|
||||
// write out cleaned CF
|
||||
SSTableReader cleaned = SSTableUtils.writeRawSSTable(keyspace, cfname, cleanedEntries, 0);
|
||||
|
||||
// verify
|
||||
BufferedRandomAccessFile origFile = new BufferedRandomAccessFile(orig.descriptor.filenameFor(SSTable.COMPONENT_DATA), "r", 8 * 1024 * 1024);
|
||||
BufferedRandomAccessFile cleanedFile = new BufferedRandomAccessFile(cleaned.descriptor.filenameFor(SSTable.COMPONENT_DATA), "r", 8 * 1024 * 1024);
|
||||
|
||||
while(origFile.getFilePointer() < origFile.length() && cleanedFile.getFilePointer() < cleanedFile.length())
|
||||
{
|
||||
assert origFile.readByte() == cleanedFile.readByte();
|
||||
}
|
||||
assert origFile.getFilePointer() == origFile.length();
|
||||
assert cleanedFile.getFilePointer() == cleanedFile.length();
|
||||
}
|
||||
}
|
||||
|
|
@ -41,6 +41,7 @@ import org.apache.cassandra.dht.Range;
|
|||
import org.apache.cassandra.io.util.DataOutputBuffer;
|
||||
import org.apache.cassandra.io.util.FileUtils;
|
||||
import org.apache.cassandra.service.StorageService;
|
||||
import org.apache.cassandra.streaming.OperationType;
|
||||
import org.apache.cassandra.thrift.IndexClause;
|
||||
import org.apache.cassandra.thrift.IndexExpression;
|
||||
import org.apache.cassandra.thrift.IndexOperator;
|
||||
|
|
@ -80,7 +81,7 @@ public class SSTableWriterTest extends CleanupHelper {
|
|||
FileUtils.deleteWithConfirm(orig.descriptor.filenameFor(Component.PRIMARY_INDEX));
|
||||
FileUtils.deleteWithConfirm(orig.descriptor.filenameFor(Component.FILTER));
|
||||
|
||||
SSTableReader sstr = CompactionManager.instance.submitSSTableBuild(orig.descriptor).get();
|
||||
SSTableReader sstr = CompactionManager.instance.submitSSTableBuild(orig.descriptor, OperationType.AES).get();
|
||||
assert sstr != null;
|
||||
ColumnFamilyStore cfs = Table.open("Keyspace1").getColumnFamilyStore("Indexed1");
|
||||
cfs.addSSTable(sstr);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
package org.apache.cassandra.service;
|
||||
|
||||
public class AntiEntropyServiceCounterTest extends AntiEntropyServiceTestAbstract
|
||||
{
|
||||
public void init()
|
||||
{
|
||||
tablename = "Keyspace5";
|
||||
cfname = "Counter1";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package org.apache.cassandra.service;
|
||||
|
||||
public class AntiEntropyServiceStandardTest extends AntiEntropyServiceTestAbstract
|
||||
{
|
||||
public void init()
|
||||
{
|
||||
tablename = "Keyspace5";
|
||||
cfname = "Standard1";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
package org.apache.cassandra.service;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.cassandra.CleanupHelper;
|
||||
import org.apache.cassandra.Util;
|
||||
import org.apache.cassandra.concurrent.Stage;
|
||||
import org.apache.cassandra.concurrent.StageManager;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.db.*;
|
||||
import org.apache.cassandra.db.filter.QueryPath;
|
||||
import org.apache.cassandra.dht.IPartitioner;
|
||||
import org.apache.cassandra.dht.Range;
|
||||
import org.apache.cassandra.dht.Token;
|
||||
import org.apache.cassandra.io.PrecompactedRow;
|
||||
import org.apache.cassandra.io.util.DataOutputBuffer;
|
||||
import org.apache.cassandra.locator.AbstractReplicationStrategy;
|
||||
import org.apache.cassandra.locator.TokenMetadata;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.MerkleTree;
|
||||
|
||||
import static org.apache.cassandra.service.AntiEntropyService.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
public abstract class AntiEntropyServiceTestAbstract extends CleanupHelper
|
||||
{
|
||||
// table and column family to test against
|
||||
public AntiEntropyService aes;
|
||||
|
||||
public String tablename;
|
||||
public String cfname;
|
||||
public TreeRequest request;
|
||||
public ColumnFamilyStore store;
|
||||
public InetAddress LOCAL, REMOTE;
|
||||
|
||||
private boolean initialized;
|
||||
|
||||
public abstract void init();
|
||||
|
||||
@Before
|
||||
public void prepare() throws Exception
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
initialized = true;
|
||||
|
||||
init();
|
||||
|
||||
LOCAL = FBUtilities.getLocalAddress();
|
||||
StorageService.instance.initServer();
|
||||
// generate a fake endpoint for which we can spoof receiving/sending trees
|
||||
REMOTE = InetAddress.getByName("127.0.0.2");
|
||||
store = null;
|
||||
for (ColumnFamilyStore cfs : Table.open(tablename).getColumnFamilyStores())
|
||||
{
|
||||
if (cfs.columnFamily.equals(cfname))
|
||||
{
|
||||
store = cfs;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert store != null : "CF not found: " + cfname;
|
||||
}
|
||||
|
||||
aes = AntiEntropyService.instance;
|
||||
TokenMetadata tmd = StorageService.instance.getTokenMetadata();
|
||||
tmd.clearUnsafe();
|
||||
StorageService.instance.setToken(StorageService.getPartitioner().getRandomToken());
|
||||
tmd.updateNormalToken(StorageService.getPartitioner().getMinimumToken(), REMOTE);
|
||||
assert tmd.isMember(REMOTE);
|
||||
|
||||
// random session id for each test
|
||||
request = new TreeRequest(UUID.randomUUID().toString(), LOCAL, new CFPair(tablename, cfname));
|
||||
}
|
||||
|
||||
@After
|
||||
public void teardown() throws Exception
|
||||
{
|
||||
flushAES();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidatorPrepare() throws Throwable
|
||||
{
|
||||
Validator validator;
|
||||
|
||||
// write
|
||||
List<RowMutation> rms = new LinkedList<RowMutation>();
|
||||
RowMutation rm;
|
||||
rm = new RowMutation(tablename, ByteBufferUtil.bytes("key1"));
|
||||
rm.add(new QueryPath(cfname, null, ByteBufferUtil.bytes("Column1")), ByteBufferUtil.bytes("asdf"), 0);
|
||||
rms.add(rm);
|
||||
Util.writeColumnFamily(rms);
|
||||
|
||||
// sample
|
||||
validator = new Validator(request);
|
||||
validator.prepare(store);
|
||||
|
||||
// and confirm that the tree was split
|
||||
assertTrue(validator.tree.size() > 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidatorComplete() throws Throwable
|
||||
{
|
||||
Validator validator = new Validator(request);
|
||||
validator.prepare(store);
|
||||
validator.complete();
|
||||
|
||||
// confirm that the tree was validated
|
||||
Token min = validator.tree.partitioner().getMinimumToken();
|
||||
assert null != validator.tree.hash(new Range(min, min));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidatorAdd() throws Throwable
|
||||
{
|
||||
Validator validator = new Validator(request);
|
||||
IPartitioner part = validator.tree.partitioner();
|
||||
Token min = part.getMinimumToken();
|
||||
Token mid = part.midpoint(min, min);
|
||||
validator.prepare(store);
|
||||
|
||||
// add a row with the minimum token
|
||||
validator.add(new PrecompactedRow(new DecoratedKey(min, ByteBufferUtil.bytes("nonsense!")),
|
||||
new DataOutputBuffer()));
|
||||
|
||||
// and a row after it
|
||||
validator.add(new PrecompactedRow(new DecoratedKey(mid, ByteBufferUtil.bytes("inconceivable!")),
|
||||
new DataOutputBuffer()));
|
||||
validator.complete();
|
||||
|
||||
// confirm that the tree was validated
|
||||
assert null != validator.tree.hash(new Range(min, min));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManualRepair() throws Throwable
|
||||
{
|
||||
AntiEntropyService.RepairSession sess = AntiEntropyService.instance.getRepairSession(tablename, cfname);
|
||||
sess.start();
|
||||
sess.blockUntilRunning();
|
||||
|
||||
// ensure that the session doesn't end without a response from REMOTE
|
||||
sess.join(100);
|
||||
assert sess.isAlive();
|
||||
|
||||
// deliver a fake response from REMOTE
|
||||
AntiEntropyService.instance.completedRequest(new TreeRequest(sess.getName(), REMOTE, request.cf));
|
||||
|
||||
// block until the repair has completed
|
||||
sess.join();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNeighborsPlusOne() throws Throwable
|
||||
{
|
||||
// generate rf+1 nodes, and ensure that all nodes are returned
|
||||
Set<InetAddress> expected = addTokens(1 + Table.open(tablename).getReplicationStrategy().getReplicationFactor());
|
||||
expected.remove(FBUtilities.getLocalAddress());
|
||||
assertEquals(expected, AntiEntropyService.getNeighbors(tablename));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNeighborsTimesTwo() throws Throwable
|
||||
{
|
||||
TokenMetadata tmd = StorageService.instance.getTokenMetadata();
|
||||
|
||||
// generate rf*2 nodes, and ensure that only neighbors specified by the ARS are returned
|
||||
addTokens(2 * Table.open(tablename).getReplicationStrategy().getReplicationFactor());
|
||||
AbstractReplicationStrategy ars = Table.open(tablename).getReplicationStrategy();
|
||||
Set<InetAddress> expected = new HashSet<InetAddress>();
|
||||
for (Range replicaRange : ars.getAddressRanges().get(FBUtilities.getLocalAddress()))
|
||||
{
|
||||
expected.addAll(ars.getRangeAddresses(tmd).get(replicaRange));
|
||||
}
|
||||
expected.remove(FBUtilities.getLocalAddress());
|
||||
assertEquals(expected, AntiEntropyService.getNeighbors(tablename));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDifferencer() throws Throwable
|
||||
{
|
||||
// generate a tree
|
||||
Validator validator = new Validator(request);
|
||||
validator.prepare(store);
|
||||
validator.complete();
|
||||
MerkleTree ltree = validator.tree;
|
||||
|
||||
// and a clone
|
||||
validator = new Validator(request);
|
||||
validator.prepare(store);
|
||||
validator.complete();
|
||||
MerkleTree rtree = validator.tree;
|
||||
|
||||
// change a range we own in one of the trees
|
||||
Token ltoken = StorageService.instance.getLocalToken();
|
||||
ltree.invalidate(ltoken);
|
||||
MerkleTree.TreeRange changed = ltree.invalids(StorageService.instance.getLocalPrimaryRange()).next();
|
||||
changed.hash("non-empty hash!".getBytes());
|
||||
// the changed range has two halves, split on our local token: both will be repaired
|
||||
// (since this keyspace has RF > N, so every node is responsible for the entire ring)
|
||||
Set<Range> interesting = new HashSet<Range>();
|
||||
interesting.add(new Range(changed.left, ltoken));
|
||||
interesting.add(new Range(ltoken, changed.right));
|
||||
|
||||
// difference the trees
|
||||
Differencer diff = new Differencer(request, ltree, rtree);
|
||||
diff.run();
|
||||
|
||||
// ensure that the changed range was recorded
|
||||
assertEquals("Wrong differing ranges", interesting, new HashSet<Range>(diff.differences));
|
||||
}
|
||||
|
||||
Set<InetAddress> addTokens(int max) throws Throwable
|
||||
{
|
||||
TokenMetadata tmd = StorageService.instance.getTokenMetadata();
|
||||
Set<InetAddress> endpoints = new HashSet<InetAddress>();
|
||||
for (int i = 1; i <= max; i++)
|
||||
{
|
||||
InetAddress endpoint = InetAddress.getByName("127.0.0." + i);
|
||||
tmd.updateNormalToken(StorageService.getPartitioner().getRandomToken(), endpoint);
|
||||
endpoints.add(endpoint);
|
||||
}
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
void flushAES() throws Exception
|
||||
{
|
||||
final ThreadPoolExecutor stage = StageManager.getStage(Stage.ANTI_ENTROPY);
|
||||
final Callable noop = new Callable<Object>()
|
||||
{
|
||||
public Boolean call()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// send two tasks through the stage: one to follow existing tasks and a second to follow tasks created by
|
||||
// those existing tasks: tasks won't recursively create more tasks
|
||||
stage.submit(noop).get(5000, TimeUnit.MILLISECONDS);
|
||||
stage.submit(noop).get(5000, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
|
@ -37,7 +37,7 @@ public class BootstrapTest extends SchemaLoader
|
|||
public void testGetNewNames() throws IOException
|
||||
{
|
||||
Descriptor desc = Descriptor.fromFilename(new File("Keyspace1", "Standard1-500-Data.db").toString());
|
||||
PendingFile inContext = new PendingFile(null, desc, "Data.db", Arrays.asList(new Pair<Long,Long>(0L, 1L)));
|
||||
PendingFile inContext = new PendingFile(null, desc, "Data.db", Arrays.asList(new Pair<Long,Long>(0L, 1L)), OperationType.BOOTSTRAP);
|
||||
|
||||
PendingFile outContext = StreamIn.getContextMapping(inContext);
|
||||
// filename and generation are expected to have changed
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ public class StreamingTransferTest extends CleanupHelper
|
|||
ranges.add(new Range(p.getMinimumToken(), p.getToken(ByteBufferUtil.bytes("key1"))));
|
||||
ranges.add(new Range(p.getToken(ByteBufferUtil.bytes("key2")), p.getMinimumToken()));
|
||||
StreamOutSession session = StreamOutSession.create(table.name, LOCAL, null);
|
||||
StreamOut.transferSSTables(session, Arrays.asList(sstable), ranges);
|
||||
StreamOut.transferSSTables(session, Arrays.asList(sstable), ranges, OperationType.BOOTSTRAP);
|
||||
session.await();
|
||||
|
||||
// confirm that the SSTable was transferred and registered
|
||||
|
|
@ -135,7 +135,7 @@ public class StreamingTransferTest extends CleanupHelper
|
|||
ranges.add(new Range(p.getMinimumToken(), p.getToken(ByteBufferUtil.bytes("transfer1"))));
|
||||
ranges.add(new Range(p.getToken(ByteBufferUtil.bytes("test2")), p.getMinimumToken()));
|
||||
StreamOutSession session = StreamOutSession.create(tablename, LOCAL, null);
|
||||
StreamOut.transferSSTables(session, Arrays.asList(sstable, sstable2), ranges);
|
||||
StreamOut.transferSSTables(session, Arrays.asList(sstable, sstable2), ranges, OperationType.BOOTSTRAP);
|
||||
session.await();
|
||||
|
||||
// confirm that the SSTable was transferred and registered
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
package org.apache.cassandra.thrift;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.cassandra.CleanupHelper;
|
||||
|
||||
public class ThriftValidationTest extends CleanupHelper
|
||||
{
|
||||
@Test(expected=InvalidRequestException.class)
|
||||
public void testValidateCommutativeWithStandard() throws InvalidRequestException
|
||||
{
|
||||
ThriftValidation.validateCommutative("Keyspace1", "Standard1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCommutativeWithCounter() throws InvalidRequestException
|
||||
{
|
||||
ThriftValidation.validateCommutative("Keyspace1", "Counter1");
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ package org.apache.cassandra.utils;
|
|||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
|
@ -85,6 +86,78 @@ public class FBUtilitiesTest
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCopyIntoBytes()
|
||||
{
|
||||
int i = 300;
|
||||
long l = 1000;
|
||||
byte[] b = new byte[20];
|
||||
FBUtilities.copyIntoBytes(b, 0, i);
|
||||
FBUtilities.copyIntoBytes(b, 4, l);
|
||||
assertEquals(i, FBUtilities.byteArrayToInt(b, 0));
|
||||
assertEquals(l, FBUtilities.byteArrayToLong(b, 4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongBytesConversions()
|
||||
{
|
||||
// positive, negative, 1 and 2 byte cases, including
|
||||
// a few edges that would foul things up unless you're careful
|
||||
// about masking away sign extension.
|
||||
long[] longs = new long[]
|
||||
{
|
||||
-20L, -127L, -128L, 0L, 1L, 127L, 128L, 65534L, 65535L, -65534L, -65535L,
|
||||
4294967294L, 4294967295L, -4294967294L, -4294967295L
|
||||
};
|
||||
|
||||
for (long l : longs) {
|
||||
byte[] ba = FBUtilities.toByteArray(l);
|
||||
long actual = FBUtilities.byteArrayToLong(ba);
|
||||
assertEquals(l, actual);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompareByteSubArrays()
|
||||
{
|
||||
byte[] bytes = new byte[16];
|
||||
|
||||
// handle null
|
||||
assert FBUtilities.compareByteSubArrays(
|
||||
null, 0, null, 0, 0) == 0;
|
||||
assert FBUtilities.compareByteSubArrays(
|
||||
null, 0, FBUtilities.toByteArray(524255231), 0, 4) == -1;
|
||||
assert FBUtilities.compareByteSubArrays(
|
||||
FBUtilities.toByteArray(524255231), 0, null, 0, 4) == 1;
|
||||
|
||||
// handle comparisons
|
||||
FBUtilities.copyIntoBytes(bytes, 3, 524255231);
|
||||
assert FBUtilities.compareByteSubArrays(
|
||||
bytes, 3, FBUtilities.toByteArray(524255231), 0, 4) == 0;
|
||||
assert FBUtilities.compareByteSubArrays(
|
||||
bytes, 3, FBUtilities.toByteArray(524255232), 0, 4) == -1;
|
||||
assert FBUtilities.compareByteSubArrays(
|
||||
bytes, 3, FBUtilities.toByteArray(524255230), 0, 4) == 1;
|
||||
|
||||
// check that incorrect length throws exception
|
||||
try
|
||||
{
|
||||
assert FBUtilities.compareByteSubArrays(
|
||||
bytes, 3, FBUtilities.toByteArray(524255231), 0, 24) == 0;
|
||||
fail("Should raise an AssertionError.");
|
||||
} catch (AssertionError ae)
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
assert FBUtilities.compareByteSubArrays(
|
||||
bytes, 3, FBUtilities.toByteArray(524255231), 0, 12) == 0;
|
||||
fail("Should raise an AssertionError.");
|
||||
} catch (AssertionError ae)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=CharacterCodingException.class)
|
||||
public void testDecode() throws IOException
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue