/*
* The MIT License
*
* Copyright (c) 2011 Dominic Williams, Daniel Washusen and contributors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.scale7.cassandra.pelops;
import static org.scale7.cassandra.pelops.Bytes.fromUTF8;
import static org.scale7.cassandra.pelops.Bytes.nullSafeGet;
import static org.scale7.cassandra.pelops.Validation.safeGetRowKey;
import static org.scale7.cassandra.pelops.Validation.validateColumn;
import static org.scale7.cassandra.pelops.Validation.validateColumnName;
import static org.scale7.cassandra.pelops.Validation.validateColumnNames;
import static org.scale7.cassandra.pelops.Validation.validateColumns;
import static org.scale7.cassandra.pelops.Validation.validateCounterColumns;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.cassandra.thrift.Column;
import org.apache.cassandra.thrift.ColumnOrSuperColumn;
import org.apache.cassandra.thrift.ConsistencyLevel;
import org.apache.cassandra.thrift.CounterColumn;
import org.apache.cassandra.thrift.CounterSuperColumn;
import org.apache.cassandra.thrift.Deletion;
import org.apache.cassandra.thrift.Mutation;
import org.apache.cassandra.thrift.SlicePredicate;
import org.apache.cassandra.thrift.SuperColumn;
import org.scale7.cassandra.pelops.exceptions.PelopsException;
import org.scale7.cassandra.pelops.pool.IThriftPool;
/**
* Facilitates the mutation of data within a Cassandra keyspace: the desired mutations should first be specified by
* calling methods such as <code>writeColumn(...)</code>, which should then be sent to Cassandra in a single batch by
* calling <code>execute(...)</code>. After the desired batch of mutations has been executed, the <code>Mutator</code>
* object can not be re-used.
*
* @author dominicwilliams
*/
public class Mutator extends Operand {
/**
* Execute the mutations that have been specified by sending them to Cassandra in a single batch.
* @param cLevel The Cassandra consistency level to be used
* @throws PelopsException
*/
public void execute(final ConsistencyLevel cLevel) throws PelopsException {
execute(cLevel, thrift.getOperandPolicy());
}
/**
* Execute the mutations that have been specified by sending them to Cassandra in a single batch.
* @param cLevel The Cassandra consistency level to be used
* @param maxOpRetries The max number of times to attempt to the op before giving up (min 1)
* @throws PelopsException
*/
public void execute(final ConsistencyLevel cLevel, int maxOpRetries) throws PelopsException {
OperandPolicy operandPolicy = thrift.getOperandPolicy().copy().setMaxOpRetries(maxOpRetries);
execute(cLevel, operandPolicy);
}
/**
* Execute the mutations that have been specified by sending them to Cassandra in a single batch.
* @param cLevel The Cassandra consistency level to be used
* @param operandPolicy The policy to use for this operation
* @throws PelopsException
*/
public void execute(final ConsistencyLevel cLevel, OperandPolicy operandPolicy) throws PelopsException {
IOperation<Void> operation = new IOperation<Void>() {
@Override
public Void execute(IThriftPool.IPooledConnection conn) throws Exception {
// Send batch mutation job to Thrift connection
conn.getAPI().batch_mutate(batch, cLevel);
// Nothing to return
return null;
}
};
tryOperation(operation, operandPolicy);
}
/**
* Write a column value.
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param column The value of the column
*/
public Mutator writeColumn(String colFamily, String rowKey, Column column) {
writeColumn(colFamily, fromUTF8(rowKey), column);
return this;
}
/**
* Write a column value.
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param column The value of the column
*/
public Mutator writeColumn(String colFamily, Bytes rowKey, Column column) {
writeColumn(colFamily, rowKey, column, this.deleteIfNull);
return this;
}
/**
* Write a column value. This method will automatically issue deletes if the deleteIfNullValue is true and the
* provided column does not have a value.
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param column The value of the column
* @param deleteIfNullValue If true and the provided column does NOT have value (as determined by the
* {@link org.apache.cassandra.thrift.Column#isSetValue()} method) then issue a
* {@link #deleteColumn(String, Bytes, Bytes) delete} instead.
*/
public Mutator writeColumn(String colFamily, Bytes rowKey, Column column, boolean deleteIfNullValue) {
if (!deleteIfNullValue || column.isSetValue()) {
writeColumnInternal(colFamily, rowKey, column);
} else {
deleteColumn(colFamily, rowKey, Bytes.fromByteArray(column.getName()));
}
return this;
}
private void writeColumnInternal(String colFamily, Bytes rowKey, Column column) {
safeGetRowKey(rowKey);
validateColumn(column);
ColumnOrSuperColumn cosc = new ColumnOrSuperColumn();
cosc.setColumn(column);
Mutation mutation = new Mutation();
mutation.setColumn_or_supercolumn(cosc);
getMutationList(colFamily, rowKey).add(mutation);
}
/**
* Write a list of columns to a key
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param columns The list of columns to write
*/
public Mutator writeColumns(String colFamily, String rowKey, List<Column> columns) {
writeColumns(colFamily, Bytes.fromUTF8(rowKey), columns);
return this;
}
/**
* Write a list of columns to a key
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param columns The list of columns to write
*/
public Mutator writeColumns(String colFamily, Bytes rowKey, List<Column> columns) {
for (Column column : columns) {
writeColumn(colFamily, rowKey, column);
}
return this;
}
/**
* Write a list of columns to a key. This method will automatically issue deletes if the deleteIfNullValue is true and the
* provided column does not have a value.
*
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param columns The list of columns to write
* @param deleteIfNullValue If true and if the provided columns do NOT have value (as determined by the
* {@link org.apache.cassandra.thrift.Column#isSetValue()} method) then issue a
* {@link #deleteColumn(String, Bytes, Bytes) delete} instead.
*/
public Mutator writeColumns(String colFamily, Bytes rowKey, List<Column> columns, boolean deleteIfNullValue) {
for (Column column : columns) {
writeColumn(colFamily, rowKey, column, deleteIfNullValue);
}
return this;
}
/**
* Write a single sub-column value to a super column. If wish to write multiple sub-columns for a
* super column, then it is more efficient to use <code>writeSubColumns</code>
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the super column
* @param subColumn The sub-column
*/
public Mutator writeSubColumn(String colFamily, String rowKey, String colName, Column subColumn) {
writeSubColumn(colFamily, rowKey, fromUTF8(colName), subColumn);
return this;
}
/**
* Write a single sub-column value to a super column. If wish to write multiple sub-columns for a
* super column, then it is more efficient to use <code>writeSubColumns</code>
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the super column
* @param subColumn The sub-column
*/
public Mutator writeSubColumn(String colFamily, String rowKey, Bytes colName, Column subColumn) {
writeSubColumn(colFamily, Bytes.fromUTF8(rowKey), colName, subColumn);
return this;
}
/**
* Write a single sub-column value to a super column. If you wish to write multiple sub-columns for a
* super column, then it is more efficient to use <code>writeSubColumns</code>
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the super column
* @param subColumn The sub-column
*/
public Mutator writeSubColumn(String colFamily, Bytes rowKey, Bytes colName, Column subColumn) {
writeSubColumns(colFamily, rowKey, colName, Arrays.asList(subColumn));
return this;
}
/**
* Write multiple sub-column values to a super column.
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the super column
* @param subColumns A list of the sub-columns to write
*/
public Mutator writeSubColumns(String colFamily, String rowKey, String colName, List<Column> subColumns) {
writeSubColumns(colFamily, rowKey, fromUTF8(colName), subColumns);
return this;
}
/**
* Write multiple sub-column values to a super column.
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the super column
* @param subColumns A list of the sub-columns to write
*/
public Mutator writeSubColumns(String colFamily, String rowKey, Bytes colName, List<Column> subColumns) {
writeSubColumns(colFamily, fromUTF8(rowKey), colName, subColumns);
return this;
}
/**
* Write multiple sub-column values to a super column.
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the super column
* @param subColumns A list of the sub-columns to write
*/
public Mutator writeSubColumns(String colFamily, Bytes rowKey, Bytes colName, List<Column> subColumns) {
writeSubColumns(colFamily, rowKey, colName, subColumns, this.deleteIfNull);
return this;
}
/**
* Write multiple sub-column values to a super column. This method will automatically delete sub columns if the
* deleteIfNullValue is true and any of the sub columns do not have a value.
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the super column
* @param subColumns A list of the sub-columns to write
* @param deleteIfNullValue If true and if the provided columns do NOT have values (as determined by the
* {@link org.apache.cassandra.thrift.Column#isSetValue()} method) then issue a
* call to {@link #deleteSubColumns(String, String, Bytes)} with the columns that
* have no values.
*/
public Mutator writeSubColumns(String colFamily, Bytes rowKey, Bytes colName, List<Column> subColumns, boolean deleteIfNullValue) {
if (deleteIfNullValue) {
// figure out if we need to worry about columns with empty values
boolean isEmptyColumnPresent = false;
for (Column subColumn : subColumns) {
if (!subColumn.isSetValue()) {
isEmptyColumnPresent = true;
break;
}
}
if (isEmptyColumnPresent) {
// separate out the columns that have a value from those that don't
List<Column> subColumnsWithValue = new ArrayList<Column>(subColumns.size());
List<Bytes> subColumnsWithoutValue = new ArrayList<Bytes>(subColumns.size());
for (Column subColumn : subColumns) {
if (subColumn.isSetValue()) {
subColumnsWithValue.add(subColumn);
} else {
subColumnsWithoutValue.add(Bytes.fromByteArray(subColumn.getName()));
}
}
deleteSubColumns(colFamily, rowKey, colName, subColumnsWithoutValue);
subColumns = subColumnsWithValue;
}
}
writeSubColumnsInternal(colFamily, rowKey, colName, subColumns);
return this;
}
/**
* Writes multiple sub-column values to a super column.
*
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the super column
* @param subColumns A list of the sub-columns to write
*/
private void writeSubColumnsInternal(String colFamily, Bytes rowKey, Bytes colName, List<Column> subColumns) {
safeGetRowKey(rowKey);
validateColumnName(colName);
validateColumns(subColumns);
SuperColumn scol = new SuperColumn(nullSafeGet(colName), subColumns);
ColumnOrSuperColumn cosc = new ColumnOrSuperColumn();
cosc.setSuper_column(scol);
Mutation mutation = new Mutation();
mutation.setColumn_or_supercolumn(cosc);
getMutationList(colFamily, rowKey).add(mutation);
}
/**
* Writes a list of counter columns to a key.
*
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param columns The list of counter columns to write
*/
public Mutator writeCounterColumns(String colFamily, String rowKey, List<CounterColumn> columns) {
return writeCounterColumns(colFamily, fromUTF8(rowKey), columns);
}
/**
* Writes a list of counter columns to a key.
*
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param columns The list of counter columns to write
*/
public Mutator writeCounterColumns(String colFamily, Bytes rowKey, List<CounterColumn> columns) {
for (CounterColumn column : columns) {
writeCounterColumn(colFamily, rowKey, column);
}
return this;
}
/**
* Writes a counter column.
*
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the counter column
* @param value The value to increment/decrement the counter by.
*/
public Mutator writeCounterColumn(String colFamily, String rowKey, String colName, long value) {
return writeCounterColumn(colFamily, fromUTF8(rowKey), newCounterColumn(colName, value));
}
/**
* Writes a counter column.
*
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the counter column
* @param value The value to increment/decrement the counter by.
*/
public Mutator writeCounterColumn(String colFamily, String rowKey, Bytes colName, long value) {
return writeCounterColumn(colFamily, fromUTF8(rowKey), newCounterColumn(colName, value));
}
/**
* Writes a counter column.
*
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the counter column
* @param value The value to increment/decrement the counter by.
*/
public Mutator writeCounterColumn(String colFamily, Bytes rowKey, Bytes colName, long value) {
return writeCounterColumn(colFamily, rowKey, newCounterColumn(colName, value));
}
/**
* Writes a counter column.
*
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param column The counter column
*/
public Mutator writeCounterColumn(String colFamily, Bytes rowKey, CounterColumn column) {
safeGetRowKey(rowKey);
validateColumn(column);
ColumnOrSuperColumn cosc = new ColumnOrSuperColumn();
cosc.setCounter_column(column);
Mutation mutation = new Mutation();
mutation.setColumn_or_supercolumn(cosc);
getMutationList(colFamily, rowKey).add(mutation);
return this;
}
/**
* Writes a sub-counter-column.
*
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the counter column
* @param subColumn The sub-counter-column
*/
public Mutator writeSubCounterColumn(String colFamily, String rowKey, String colName, CounterColumn subColumn) {
return writeSubCounterColumn(colFamily, fromUTF8(rowKey), fromUTF8(colName), subColumn);
}
/**
* Writes a sub-counter-column.
*
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the counter column
* @param subColumn The sub-counter-column
*/
public Mutator writeSubCounterColumn(String colFamily, String rowKey, Bytes colName, CounterColumn subColumn) {
return writeSubCounterColumn(colFamily, fromUTF8(rowKey), colName, subColumn);
}
/**
* Writes a sub-counter-column.
*
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the counter column
* @param subColumn The sub-counter-column
*/
public Mutator writeSubCounterColumn(String colFamily, Bytes rowKey, Bytes colName, CounterColumn subColumn) {
writeSubCounterColumns(colFamily, rowKey, colName, Arrays.asList(subColumn));
return this;
}
/**
* Writes multiple sub-counter-column values to a super column.
*
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the super column
* @param subColumns A list of the sub-counter-columns to write
*/
public Mutator writeSubCounterColumns(String colFamily, Bytes rowKey, Bytes colName, List<CounterColumn> subColumns) {
safeGetRowKey(rowKey);
validateColumnName(colName);
validateCounterColumns(subColumns);
CounterSuperColumn scol = new CounterSuperColumn(nullSafeGet(colName), subColumns);
ColumnOrSuperColumn cosc = new ColumnOrSuperColumn();
cosc.setCounter_super_column(scol);
Mutation mutation = new Mutation();
mutation.setColumn_or_supercolumn(cosc);
getMutationList(colFamily, rowKey).add(mutation);
return this;
}
/**
* Delete a column or super column
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the column or super column to delete.
*/
public Mutator deleteColumn(String colFamily, String rowKey, String colName) {
deleteColumn(colFamily, rowKey, fromUTF8(colName));
return this;
}
/**
* Delete a column or super column.
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the column or super column to delete.
*/
public Mutator deleteColumn(String colFamily, String rowKey, Bytes colName) {
deleteColumn(colFamily, Bytes.fromUTF8(rowKey), colName);
return this;
}
/**
* Delete a column or super column.
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the column or super column to delete.
*/
public Mutator deleteColumn(String colFamily, Bytes rowKey, Bytes colName) {
deleteColumns(colFamily, rowKey, Arrays.asList(colName));
return this;
}
/**
* Delete a list of columns or super columns.
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colNames The column and/or super column names to delete
*/
public Mutator deleteColumns(String colFamily, String rowKey, Bytes... colNames) {
deleteColumns(colFamily, Bytes.fromUTF8(rowKey), Arrays.asList(colNames));
return this;
}
/**
* Delete a list of columns or super columns.
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colNames The column and/or super column names to delete
*/
public Mutator deleteColumns(String colFamily, Bytes rowKey, Bytes... colNames) {
deleteColumns(colFamily, rowKey, Arrays.asList(colNames));
return this;
}
/**
* Delete a list of columns or super columns.
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colNames The column and/or super column names to delete
*/
public Mutator deleteColumns(String colFamily, String rowKey, String... colNames) {
List<Bytes> colNameList = new ArrayList<Bytes>(colNames.length);
for (String colName : colNames)
colNameList.add(fromUTF8(colName));
deleteColumns(colFamily, Bytes.fromUTF8(rowKey), colNameList);
return this;
}
/**
* Delete a list of columns or super columns.
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colNames The column and/or super column names to delete
*/
public Mutator deleteColumns(String colFamily, String rowKey, List<Bytes> colNames) {
deleteColumns(colFamily, Bytes.fromUTF8(rowKey), colNames);
return this;
}
/**
* Delete a list of columns or super columns.
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colNames The column and/or super column names to delete
*/
public Mutator deleteColumns(String colFamily, Bytes rowKey, List<Bytes> colNames) {
safeGetRowKey(rowKey);
validateColumnNames(colNames);
SlicePredicate pred = new SlicePredicate();
pred.setColumn_names(Bytes.transformBytesToList(colNames));
Deletion deletion = new Deletion();
deletion.setTimestamp(timestamp);
deletion.setPredicate(pred);
Mutation mutation = new Mutation();
mutation.setDeletion(deletion);
getMutationList(colFamily, rowKey).add(mutation);
return this;
}
/**
* Delete a column or super column.
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the super column to modify.
* @param subColName The name of the sub-column to delete.
*/
public Mutator deleteSubColumn(String colFamily, String rowKey, String colName, String subColName) {
deleteSubColumn(colFamily, rowKey, fromUTF8(colName), fromUTF8(subColName));
return this;
}
/**
* Delete a column or super column.
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the super column to modify.
* @param subColName The name of the sub-column to delete.
*/
public Mutator deleteSubColumn(String colFamily, String rowKey, Bytes colName, String subColName) {
deleteSubColumn(colFamily, rowKey, colName, fromUTF8(subColName));
return this;
}
/**
* Delete a column or super column.
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the super column to modify.
* @param subColName The name of the sub-column to delete.
*/
public Mutator deleteSubColumn(String colFamily, String rowKey, String colName, Bytes subColName) {
deleteSubColumn(colFamily, rowKey, fromUTF8(colName), subColName);
return this;
}
/**
* Delete a column or super column.
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the super column to modify.
* @param subColName The name of the sub-column to delete.
*/
public Mutator deleteSubColumn(String colFamily, String rowKey, Bytes colName, Bytes subColName) {
deleteSubColumn(colFamily, Bytes.fromUTF8(rowKey), colName, subColName);
return this;
}
/**
* Delete a column or super column.
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the super column to modify.
* @param subColName The name of the sub-column to delete.
*/
public Mutator deleteSubColumn(String colFamily, Bytes rowKey, Bytes colName, Bytes subColName) {
List<Bytes> subColNames = new ArrayList<Bytes>(1);
subColNames.add(subColName);
deleteSubColumns(colFamily, rowKey, colName, subColNames);
return this;
}
/**
* Delete a list of sub-columns
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the super column to modify
* @param subColNames The sub-column names to delete (empty value will result in all columns being removed)
*/
public Mutator deleteSubColumns(String colFamily, String rowKey, String colName, String... subColNames) {
deleteSubColumns(colFamily, rowKey, fromUTF8(colName), subColNames);
return this;
}
/**
* Delete a list of sub-columns
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the super column to modify
* @param subColNames The sub-column names to delete (empty value will result in all columns being removed)
*/
public Mutator deleteSubColumns(String colFamily, String rowKey, Bytes colName, String... subColNames) {
deleteSubColumns(colFamily, Bytes.fromUTF8(rowKey), colName, subColNames);
return this;
}
/**
* Delete a list of sub-columns
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the super column to modify
* @param subColNames The sub-column names to delete (empty value will result in all columns being removed)
*/
public Mutator deleteSubColumns(String colFamily, Bytes rowKey, Bytes colName, String... subColNames) {
List<Bytes> subColNamesList = new ArrayList<Bytes>(subColNames.length);
for (String subColName : subColNames)
subColNamesList.add(fromUTF8(subColName));
deleteSubColumns(colFamily, rowKey, colName, subColNamesList);
return this;
}
/**
* Delete all sub-columns
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the super column to modify
*/
public Mutator deleteSubColumns(String colFamily, String rowKey, String colName) {
deleteSubColumns(colFamily, fromUTF8(rowKey), fromUTF8(colName), (List<Bytes>) null);
return this;
}
/**
* Delete a list of sub-columns
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the super column to modify
* @param subColNames The sub-column names to delete
*/
public Mutator deleteSubColumns(String colFamily, String rowKey, String colName, List<Bytes> subColNames) {
deleteSubColumns(colFamily, fromUTF8(rowKey), fromUTF8(colName), subColNames);
return this;
}
/**
* Delete all sub-columns
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the super column to modify
*/
public Mutator deleteSubColumns(String colFamily, String rowKey, Bytes colName) {
deleteSubColumns(colFamily, fromUTF8(rowKey), colName, (List<Bytes>) null);
return this;
}
/**
* Delete a list of sub-columns
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the super column to modify
* @param subColNames The sub-column names to delete
*/
public Mutator deleteSubColumns(String colFamily, String rowKey, Bytes colName, List<Bytes> subColNames) {
deleteSubColumns(colFamily, fromUTF8(rowKey), colName, subColNames);
return this;
}
/**
* Delete a list of sub-columns
* @param colFamily The column family
* @param rowKey The key of the row to modify
* @param colName The name of the super column to modify
* @param subColNames The sub-column names to delete
*/
public Mutator deleteSubColumns(String colFamily, Bytes rowKey, Bytes colName, List<Bytes> subColNames) {
safeGetRowKey(rowKey);
validateColumnName(colName);
validateColumnNames(subColNames);
Deletion deletion = new Deletion();
deletion.setTimestamp(timestamp);
deletion.setSuper_column(nullSafeGet(colName));
// CASSANDRA-1027 allows for a null predicate
deletion.setPredicate(
subColNames != null && !subColNames.isEmpty() ?
new SlicePredicate().setColumn_names(Bytes.transformBytesToList(subColNames)) : null
);
Mutation mutation = new Mutation();
mutation.setDeletion(deletion);
getMutationList(colFamily, rowKey).add(mutation);
return this;
}
/**
* Create new Column object with the time stamp passed to the constructor
* @param colName The column name
* @param colValue The column value
* @return An appropriate <code>Column</code> object
*/
public Column newColumn(String colName, String colValue) {
return newColumn(fromUTF8(colName), fromUTF8(colValue));
}
/**
* Create new Column object with the time stamp passed to the constructor
* @param colName The column name
* @param colValue The column value
* @param ttl The time to live (in seconds) for the column
* @return An appropriate <code>Column</code> object
*/
public Column newColumn(String colName, String colValue, int ttl) {
return newColumn(fromUTF8(colName), fromUTF8(colValue), ttl);
}
/**
* Create new Column object with the time stamp passed to the constructor
* @param colName The column name
* @param colValue The column value
* @return An appropriate <code>Column</code> object
*/
public Column newColumn(Bytes colName, String colValue) {
return newColumn(colName, fromUTF8(colValue));
}
/**
* Create new Column object with the time stamp passed to the constructor
* @param colName The column name
* @param colValue The column value
* @param ttl The time to live (in seconds) for the column
* @return An appropriate <code>Column</code> object
*/
public Column newColumn(Bytes colName, String colValue, int ttl) {
return newColumn(colName, fromUTF8(colValue), ttl);
}
/**
* Create new Column object with an empty value and the time stamp passed to the constructor
* @param colName The column name
* @return An appropriate <code>Column</code> object
*/
public Column newColumn(String colName) {
return newColumn(fromUTF8(colName), Bytes.EMPTY);
}
/**
* Create new Column object with the time stamp passed to the constructor
* @param colName The column name
* @param colValue The column value
* @return An appropriate <code>Column</code> object
*/
public Column newColumn(String colName, Bytes colValue) {
return newColumn(fromUTF8(colName), colValue);
}
/**
* Create new Column object with an empty value and the time stamp passed to the constructor
* @param colName The column name
* @param ttl The time to live (in seconds) for the column
* @return An appropriate <code>Column</code> object
*/
public Column newColumn(String colName, int ttl) {
return newColumn(fromUTF8(colName), Bytes.EMPTY, ttl);
}
/**
* Create new Column object with the time stamp passed to the constructor
* @param colName The column name
* @param colValue The column value
* @param ttl The time to live (in seconds) for the column
* @return An appropriate <code>Column</code> object
*/
public Column newColumn(String colName, Bytes colValue, int ttl) {
return newColumn(fromUTF8(colName), colValue, ttl);
}
/**
* Create new Column object with an empty value and the time stamp passed to the constructor
* @param colName The column name
* @return An appropriate <code>Column</code> object
*/
public Column newColumn(Bytes colName) {
return newColumn(colName, Bytes.EMPTY);
}
/**
* Create new Column object with the time stamp passed to the constructor
* @param colName The column name
* @param colValue The column value
* @return An appropriate <code>Column</code> object
*/
public Column newColumn(Bytes colName, Bytes colValue) {
return newColumn(colName, colValue, this.ttl);
}
/**
* Create new Column object with an empty value and the time stamp passed to the constructor
* @param colName The column name
* @param ttl The time to live (in seconds) for the column
* @return An appropriate <code>Column</code> object
*/
public Column newColumn(Bytes colName, int ttl) {
return newColumn(colName, Bytes.EMPTY, ttl);
}
/**
* Create new Column object with the time stamp passed to the constructor
* @param colName The column name
* @param colValue The column value
* @param ttl The time to live (in seconds) for the column (-1 for default)
* @return An appropriate <code>Column</code> object
*/
public Column newColumn(Bytes colName, Bytes colValue, int ttl) {
Column column = new Column(nullSafeGet(colName));
column.setValue(nullSafeGet(colValue));
column.setTimestamp(timestamp);
if (ttl != NO_TTL) column.setTtl(ttl);
return column;
}
/**
* Create a list of <code>Column</code> objects.
* @param columns The columns from which to compose the list
* @return A list of <code>Column</code> objects
*/
public List<Column> newColumnList(Column... columns) {
ArrayList<Column> list = new ArrayList<Column>(columns.length);
for (Column column : columns)
list.add(column);
return list;
}
/**
* Creates a new counter column.
*
* @param colName The column name.
* @param value The value to increment/decrement the counter by.
* @return An appropriate <code>CounterColumn</code> object
*/
public CounterColumn newCounterColumn(String colName, long value) {
return newCounterColumn(fromUTF8(colName), value);
}
/**
* Create a new counter column.
* @param colName The column name.
* @param value The value to increment/decrement the counter by.
* @return An appropriate <code>CounterColumn</code> object
*/
public CounterColumn newCounterColumn(Bytes colName, long value) {
return new CounterColumn(colName.getBytes(), value);
}
/**
* Get the default time stamp used by this <code>Mutator</code> instance as a byte[].
* @param microsToMillis If the time stamp is UTC microseconds (as is a self-constructed time stamp), whether to convert this into a standard milliseconds value
* @return A byte array containing the time stamp <code>long</code> value
*/
public Bytes getMutationTimestamp(boolean microsToMillis) {
long result = timestamp;
if (microsToMillis)
result /= 1000;
return Bytes.fromLong(result);
}
/**
* Get the raw time stamp value used by this <code>Mutator</code> instance.
* @return The raw time stamp value being used
*/
public long getMutationTimestampValue() {
return timestamp;
}
@SuppressWarnings("serial")
class MutationList extends ArrayList<Mutation> {}
@SuppressWarnings("serial")
class MutationsByCf extends HashMap<String, List<Mutation>> {}
@SuppressWarnings("serial")
class MutationsByKey extends HashMap<ByteBuffer, Map<String, List<Mutation>>> {}
/**
* Used to indicate that the ttl property on column instances should not be set.
*/
public static final int NO_TTL = -1;
private final Map<ByteBuffer, Map<String, List<Mutation>>> batch;
protected final long timestamp;
protected final boolean deleteIfNull;
protected final int ttl;
/**
* Create a batch mutation operation.
*/
public Mutator(IThriftPool thrift) {
this(thrift, System.currentTimeMillis() * 1000, thrift.getOperandPolicy().isDeleteIfNull());
}
/**
* Create a batch mutation operation.
* @param timestamp The time stamp to use for the operation.
*/
public Mutator(IThriftPool thrift, long timestamp, boolean deleteIfNull) {
this(thrift, timestamp, deleteIfNull, NO_TTL);
}
/**
* Create a batch mutation operation.
* @param thrift the pool
* @param timestamp The time stamp to use for the operation.
* @param deleteIfNull determine if null values on columns will result in a delete
* @param ttl the ttl (in seconds) that columns created using the various {@link #newColumn(Bytes, Bytes)}
* helper methods will default to (null to indicate no default)
*/
public Mutator(IThriftPool thrift, long timestamp, boolean deleteIfNull, int ttl) {
super(thrift);
this.timestamp = timestamp;
this.deleteIfNull = deleteIfNull;
this.ttl = ttl;
batch = new MutationsByKey();
}
protected Map<ByteBuffer, Map<String, List<Mutation>>> getBatch() {
return batch;
}
protected MutationList getMutationList(String colFamily, Bytes key) {
ByteBuffer keyBuffer = key.getBytes();
MutationsByCf mutsByCf = (MutationsByCf) batch.get(keyBuffer);
if (mutsByCf == null) {
mutsByCf = new MutationsByCf();
batch.put(keyBuffer, mutsByCf);
}
MutationList mutList = (MutationList) mutsByCf.get(colFamily);
if (mutList == null) {
mutList = new MutationList();
mutsByCf.put(colFamily, mutList);
}
return mutList;
}
}