This is a wierd revert to fix some issues. Some changes will need to be re-applied.

git-svn-id: https://svn.apache.org/repos/asf/incubator/cassandra/trunk@759026 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Avinash Lakshman 2009-03-27 05:39:40 +00:00
parent f5d1a1289c
commit 964dd9bb57
28 changed files with 2205 additions and 1353 deletions

View File

@ -31,13 +31,13 @@ import java.util.StringTokenizer;
abstract class AbstractColumnFactory
{
private static Map<String, AbstractColumnFactory> columnFactory_ = new HashMap<String, AbstractColumnFactory>();
static
{
columnFactory_.put(ColumnFamily.getColumnType("Standard"),new ColumnFactory());
columnFactory_.put(ColumnFamily.getColumnType("Super"),new SuperColumnFactory());
}
static AbstractColumnFactory getColumnFactory(String columnType)
{
/* Create based on the type required. */
@ -46,11 +46,10 @@ abstract class AbstractColumnFactory
else
return columnFactory_.get("Super");
}
public abstract IColumn createColumn(String name);
public abstract IColumn createColumn(String name, byte[] value);
public abstract IColumn createColumn(String name, byte[] value, long timestamp);
public abstract IColumn createColumn(String name, byte[] value, long timestamp, boolean deleted);
public abstract IColumn createColumn(String name, byte[] value, long timestamp);
public abstract ICompactSerializer2<IColumn> createColumnSerializer();
}
@ -60,21 +59,17 @@ class ColumnFactory extends AbstractColumnFactory
{
return new Column(name);
}
public IColumn createColumn(String name, byte[] value)
{
return new Column(name, value);
}
public IColumn createColumn(String name, byte[] value, long timestamp)
{
return new Column(name, value, timestamp);
}
public IColumn createColumn(String name, byte[] value, long timestamp, boolean deleted) {
return new Column(name, value, timestamp, deleted);
}
public ICompactSerializer2<IColumn> createColumnSerializer()
{
return Column.serializer();
@ -108,28 +103,29 @@ class SuperColumnFactory extends AbstractColumnFactory
}
return superColumn;
}
public IColumn createColumn(String name, byte[] value)
{
return createColumn(name, value, 0);
}
public IColumn createColumn(String name, byte[] value, long timestamp)
{
return createColumn(name, value, timestamp, false);
}
public IColumn createColumn(String name, byte[] value, long timestamp, boolean deleted)
{
String[] values = SuperColumnFactory.getSuperColumnAndColumn(name);
if ( values.length != 2 )
throw new IllegalArgumentException("Super Column " + name + " in invalid format. Must be in <super column name>:<column name> format.");
IColumn superColumn = new SuperColumn(values[0]);
IColumn subColumn = new Column(values[1], value, timestamp, deleted);
IColumn subColumn = new Column(values[1], value);
superColumn.addColumn(values[1], subColumn);
return superColumn;
}
public IColumn createColumn(String name, byte[] value, long timestamp)
{
String[] values = SuperColumnFactory.getSuperColumnAndColumn(name);
if ( values.length != 2 )
throw new IllegalArgumentException("Super Column " + name + " in invalid format. Must be in <super column name>:<column name> format.");
IColumn superColumn = new SuperColumn(values[0]);
IColumn subColumn = new Column(values[1], value, timestamp);
superColumn.addColumn(values[1], subColumn);
return superColumn;
}
public ICompactSerializer2<IColumn> createColumnSerializer()
{
return SuperColumn.serializer();

View File

@ -29,9 +29,8 @@ import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.utils.BloomFilter;
import org.apache.cassandra.io.SSTable;
import org.apache.cassandra.utils.BloomFilter;
import org.apache.log4j.Logger;
import org.cliffc.high_scale_lib.NonBlockingHashMap;

View File

@ -18,41 +18,60 @@
package org.apache.cassandra.db;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.lang.ArrayUtils;
import org.apache.cassandra.io.DataInputBuffer;
import org.apache.cassandra.io.IFileReader;
import org.apache.cassandra.io.IFileWriter;
import org.apache.cassandra.utils.FBUtilities;
import org.apache.cassandra.utils.HashingSchemes;
import org.apache.cassandra.utils.LogUtil;
import org.apache.log4j.Logger;
/**
* Column is immutable, which prevents all kinds of confusion in a multithreaded environment.
* (TODO: look at making SuperColumn immutable too. This is trickier but is probably doable
* with something like PCollections -- http://code.google.com
*
* Author : Avinash Lakshman ( alakshman@facebook.com ) & Prashant Malik ( pmalik@facebook.com )
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
*/
public final class Column implements IColumn
public final class Column implements IColumn, Serializable
{
private static ColumnSerializer serializer_ = new ColumnSerializer();
private static Logger logger_ = Logger.getLogger(SuperColumn.class);
private static ICompactSerializer2<IColumn> serializer_;
private final static String seperator_ = ":";
static
{
serializer_ = new ColumnSerializer();
}
static ColumnSerializer serializer()
static ICompactSerializer2<IColumn> serializer()
{
return serializer_;
}
private final String name;
private final byte[] value;
private final long timestamp;
private final boolean isMarkedForDelete;
private String name_;
private byte[] value_ = new byte[0];
private long timestamp_ = 0;
private transient AtomicBoolean isMarkedForDelete_;
/* CTOR for JAXB */
Column()
{
}
Column(String name)
{
this(name, ArrayUtils.EMPTY_BYTE_ARRAY);
name_ = name;
}
Column(String name, byte[] value)
@ -62,71 +81,54 @@ public final class Column implements IColumn
Column(String name, byte[] value, long timestamp)
{
this(name, value, timestamp, false);
}
Column(String name, byte[] value, long timestamp, boolean isDeleted)
{
assert name != null;
assert value != null;
this.name = name;
this.value = value;
this.timestamp = timestamp;
isMarkedForDelete = isDeleted;
this(name);
value_ = value;
timestamp_ = timestamp;
}
public String name()
{
return name;
}
public IColumn getSubColumn(String columnName)
{
throw new UnsupportedOperationException("This operation is unsupported on simple columns.");
return name_;
}
public byte[] value()
{
return value;
return value_;
}
public byte[] value(String key)
{
throw new UnsupportedOperationException("This operation is unsupported on simple columns.");
throw new UnsupportedOperationException("This operation is unsupported on simple columns.");
}
public Collection<IColumn> getSubColumns()
{
throw new UnsupportedOperationException("This operation is unsupported on simple columns.");
throw new UnsupportedOperationException("This operation is unsupported on simple columns.");
}
public IColumn getSubColumn( String columnName )
{
throw new UnsupportedOperationException("This operation is unsupported on simple columns.");
}
public int getObjectCount()
{
return 1;
return 1;
}
public long timestamp()
{
return timestamp;
return timestamp_;
}
public long timestamp(String key)
{
throw new UnsupportedOperationException("This operation is unsupported on simple columns.");
throw new UnsupportedOperationException("This operation is unsupported on simple columns.");
}
public boolean isMarkedForDelete()
{
return isMarkedForDelete;
}
public long getMarkedForDeleteAt()
{
if (!isMarkedForDelete())
{
throw new IllegalStateException("column is not marked for delete");
}
return timestamp;
return (isMarkedForDelete_ != null) ? isMarkedForDelete_.get() : false;
}
public int size()
@ -140,11 +142,11 @@ public final class Column implements IColumn
* + entire byte array.
*/
/*
* We store the string as UTF-8 encoded, so when we calculate the length, it
* should be converted to UTF-8.
*/
return IColumn.UtfPrefix_ + FBUtilities.getUTF8Length(name) + DBConstants.boolSize_ + DBConstants.tsSize_ + DBConstants.intSize_ + value.length;
/*
* We store the string as UTF-8 encoded, so when we calculate the length, it
* should be converted to UTF-8.
*/
return IColumn.UtfPrefix_ + FBUtilities.getUTF8Length(name_) + DBConstants.boolSize_ + DBConstants.tsSize_ + DBConstants.intSize_ + value_.length;
}
/*
@ -153,43 +155,112 @@ public final class Column implements IColumn
*/
public int serializedSize()
{
return size();
return size();
}
public void addColumn(String name, IColumn column)
{
throw new UnsupportedOperationException("This operation is not supported for simple columns.");
throw new UnsupportedOperationException("This operation is not supported for simple columns.");
}
public void delete()
{
if ( isMarkedForDelete_ == null )
isMarkedForDelete_ = new AtomicBoolean(true);
else
isMarkedForDelete_.set(true);
value_ = new byte[0];
}
public void repair(IColumn column)
{
if( timestamp() < column.timestamp() )
{
value_ = column.value();
timestamp_ = column.timestamp();
}
}
public IColumn diff(IColumn column)
{
if (timestamp() < column.timestamp())
{
return column;
}
return null;
IColumn columnDiff = null;
if( timestamp() < column.timestamp() )
{
columnDiff = new Column(column.name(),column.value(),column.timestamp());
}
return columnDiff;
}
/*
* Resolve the column by comparing timestamps
* if a newer vaue is being input
* take the change else ignore .
*
*/
public boolean putColumn(IColumn column)
{
if ( !(column instanceof Column))
throw new UnsupportedOperationException("Only Column objects should be put here");
if( !name_.equals(column.name()))
throw new IllegalArgumentException("The name should match the name of the current column or super column");
if(timestamp_ <= column.timestamp())
{
return true;
}
return false;
}
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(name);
sb.append(":");
sb.append(isMarkedForDelete());
sb.append(":");
sb.append(value().length);
sb.append("@");
sb.append(timestamp());
return sb.toString();
StringBuilder sb = new StringBuilder();
sb.append(name_);
sb.append(":");
sb.append(isMarkedForDelete());
sb.append(":");
sb.append(timestamp());
sb.append(":");
sb.append(value().length);
sb.append(":");
sb.append(value());
sb.append(":");
return sb.toString();
}
public byte[] digest()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(name);
stringBuilder.append(":");
stringBuilder.append(timestamp);
return stringBuilder.toString().getBytes();
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(name_);
stringBuilder.append(seperator_);
stringBuilder.append(timestamp_);
return stringBuilder.toString().getBytes();
}
/**
* This method is basically implemented for Writable interface
* for M/R.
*/
public void readFields(DataInput in) throws IOException
{
name_ = in.readUTF();
boolean delete = in.readBoolean();
long ts = in.readLong();
int size = in.readInt();
byte[] value = new byte[size];
in.readFully(value);
if ( delete )
delete();
}
/**
* This method is basically implemented for Writable interface
* for M/R.
*/
public void write(DataOutput out) throws IOException
{
out.writeUTF(name_);
out.writeBoolean(isMarkedForDelete());
out.writeLong(timestamp_);
out.writeInt(value().length);
out.write(value());
}
}
@ -213,7 +284,9 @@ class ColumnSerializer implements ICompactSerializer2<IColumn>
int size = dis.readInt();
byte[] value = new byte[size];
dis.readFully(value);
column = new Column(name, value, ts, delete);
column = new Column(name, value, ts);
if ( delete )
column.delete();
return column;
}
@ -230,7 +303,7 @@ class ColumnSerializer implements ICompactSerializer2<IColumn>
{
if ( dis.available() == 0 )
return null;
String name = dis.readUTF();
IColumn column = new Column(name);
column = filter.filter(column, dis);
@ -266,8 +339,8 @@ class ColumnSerializer implements ICompactSerializer2<IColumn>
/*
* If this is being called with identity filter
* since a column name is passed in we know
* that this is a final call
* Hence if the column is found set the filter to done
* that this is a final call
* Hence if the column is found set the filter to done
* so that we do not look for the column in further files
*/
IdentityFilter f = (IdentityFilter)filter;
@ -295,6 +368,5 @@ class ColumnSerializer implements ICompactSerializer2<IColumn>
/* size of the column */
int size = dis.readInt();
dis.skip(size);
}
}
}

View File

@ -28,123 +28,127 @@ import java.util.Comparator;
public class ColumnComparatorFactory
{
public static enum ComparatorType
{
NAME,
TIMESTAMP
}
public static enum ComparatorType
{
NAME,
TIMESTAMP
}
private static Comparator<IColumn> nameComparator_ = new ColumnNameComparator();
private static Comparator<IColumn> timestampComparator_ = new ColumnTimestampComparator();
private static Comparator<IColumn> nameComparator_ = new ColumnNameComparator();
private static Comparator<IColumn> timestampComparator_ = new ColumnTimestampComparator();
public static Comparator<IColumn> getComparator(ComparatorType comparatorType)
{
Comparator<IColumn> columnComparator = timestampComparator_;
public static Comparator<IColumn> getComparator(ComparatorType comparatorType)
{
Comparator<IColumn> columnComparator = timestampComparator_;
switch (comparatorType)
{
case NAME:
columnComparator = nameComparator_;
break;
switch(comparatorType)
{
case NAME:
columnComparator = nameComparator_;
break;
case TIMESTAMP:
case TIMESTAMP:
default:
columnComparator = timestampComparator_;
break;
}
default:
columnComparator = timestampComparator_;
break;
}
return columnComparator;
}
return columnComparator;
}
public static Comparator<IColumn> getComparator(int comparatorTypeInt)
{
ComparatorType comparatorType = ComparatorType.NAME;
public static Comparator<IColumn> getComparator(int comparatorTypeInt)
{
ComparatorType comparatorType = ComparatorType.NAME;
if (comparatorTypeInt == ComparatorType.NAME.ordinal())
{
comparatorType = ComparatorType.NAME;
}
else if (comparatorTypeInt == ComparatorType.TIMESTAMP.ordinal())
{
comparatorType = ComparatorType.TIMESTAMP;
}
return getComparator(comparatorType);
}
if(comparatorTypeInt == ComparatorType.NAME.ordinal())
{
comparatorType = ComparatorType.NAME;
}
else if(comparatorTypeInt == ComparatorType.TIMESTAMP.ordinal())
{
comparatorType = ComparatorType.TIMESTAMP;
}
return getComparator(comparatorType);
}
public static void main(String[] args)
{
IColumn col1 = new Column("Column-9");
IColumn col2 = new Column("Column-10");
System.out.println("Result of compare: " + getComparator(ComparatorType.NAME).compare(col1, col2));
}
}
abstract class AbstractColumnComparator implements Comparator<IColumn>, Serializable
{
protected ColumnComparatorFactory.ComparatorType comparatorType_;
protected ColumnComparatorFactory.ComparatorType comparatorType_;
public AbstractColumnComparator(ColumnComparatorFactory.ComparatorType comparatorType)
{
comparatorType_ = comparatorType;
}
public AbstractColumnComparator(ColumnComparatorFactory.ComparatorType comparatorType)
{
comparatorType_ = comparatorType;
}
ColumnComparatorFactory.ComparatorType getComparatorType()
{
return comparatorType_;
}
ColumnComparatorFactory.ComparatorType getComparatorType()
{
return comparatorType_;
}
}
class ColumnTimestampComparator extends AbstractColumnComparator
{
ColumnTimestampComparator()
{
super(ColumnComparatorFactory.ComparatorType.TIMESTAMP);
}
ColumnTimestampComparator()
{
super(ColumnComparatorFactory.ComparatorType.TIMESTAMP);
}
/* if the time-stamps are the same then sort by names */
/* if the time-stamps are the same then sort by names */
public int compare(IColumn column1, IColumn column2)
{
assert column1.getClass() == column2.getClass();
/* inverse sort by time to get hte latest first */
long result = column2.timestamp() - column1.timestamp();
int finalResult = 0;
if (result == 0)
{
result = column1.name().compareTo(column2.name());
}
if (result > 0)
{
finalResult = 1;
}
if (result < 0)
{
finalResult = -1;
}
/* inverse sort by time to get hte latest first */
long result = column2.timestamp() - column1.timestamp();
int finalResult = 0;
if(result == 0)
{
result = column1.name().compareTo(column2.name());
}
if(result > 0)
{
finalResult = 1;
}
if( result < 0 )
{
finalResult = -1;
}
return finalResult;
}
}
class ColumnNameComparator extends AbstractColumnComparator
{
ColumnNameComparator()
{
super(ColumnComparatorFactory.ComparatorType.NAME);
}
ColumnNameComparator()
{
super(ColumnComparatorFactory.ComparatorType.NAME);
}
/* if the names are the same then sort by time-stamps */
public int compare(IColumn column1, IColumn column2)
{
assert column1.getClass() == column2.getClass();
long result = column1.name().compareTo(column2.name());
int finalResult = 0;
if (result == 0 && (column1 instanceof Column))
{
/* inverse sort by time to get the latest first */
result = column2.timestamp() - column1.timestamp();
}
if (result > 0)
{
finalResult = 1;
}
if (result < 0)
{
finalResult = -1;
}
long result = column1.name().compareTo(column2.name());
int finalResult = 0;
if(result == 0)
{
/* inverse sort by time to get hte latest first */
result = column2.timestamp() - column1.timestamp();
}
if(result > 0)
{
finalResult = 1;
}
if( result < 0 )
{
finalResult = -1;
}
return finalResult;
}
}

View File

@ -18,29 +18,28 @@
package org.apache.cassandra.db;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Proxy;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.utils.FBUtilities;
import org.apache.cassandra.utils.HashingSchemes;
import org.apache.log4j.Logger;
import org.apache.cassandra.io.*;
/**
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
*/
public final class ColumnFamily
public final class ColumnFamily implements Serializable
{
private static ICompactSerializer2<ColumnFamily> serializer_;
public static final short utfPrefix_ = 2;
@ -57,7 +56,7 @@ public final class ColumnFamily
/* TODO: These are the various column types. Hard coded for now. */
columnTypes_.put("Standard", "Standard");
columnTypes_.put("Super", "Super");
indexTypes_.put("Name", "Name");
indexTypes_.put("Time", "Time");
}
@ -71,7 +70,7 @@ public final class ColumnFamily
* This method returns the serializer whose methods are
* preprocessed by a dynamic proxy.
*/
public static ICompactSerializer2<ColumnFamily> serializerWithIndexes()
public static ICompactSerializer2<ColumnFamily> serializer2()
{
return (ICompactSerializer2<ColumnFamily>)Proxy.newProxyInstance( ColumnFamily.class.getClassLoader(), new Class[]{ICompactSerializer2.class}, new CompactSerializerInvocationHandler<ColumnFamily>(serializer_) );
}
@ -95,9 +94,9 @@ public final class ColumnFamily
private String name_;
private transient ICompactSerializer2<IColumn> columnSerializer_;
private long markedForDeleteAt = Long.MIN_VALUE;
private AtomicInteger size_ = new AtomicInteger(0);
private transient ICompactSerializer2<IColumn> columnSerializer_;
private transient AtomicBoolean isMarkedForDelete_;
private AtomicInteger size_ = new AtomicInteger(0);
private EfficientBidiMap columns_;
private Comparator<IColumn> columnComparator_;
@ -123,16 +122,20 @@ public final class ColumnFamily
return columnComparator_;
}
public ColumnFamily(String cfName)
ColumnFamily()
{
name_ = cfName;
}
public ColumnFamily(String cf)
{
name_ = cf;
createColumnFactoryAndColumnSerializer();
}
public ColumnFamily(String cfName, String columnType)
public ColumnFamily(String cf, String columnType)
{
this(cfName);
name_ = cf;
createColumnFactoryAndColumnSerializer(columnType);
}
@ -165,7 +168,7 @@ public final class ColumnFamily
ColumnFamily cloneMe()
{
ColumnFamily cf = new ColumnFamily(name_);
cf.markedForDeleteAt = markedForDeleteAt;
cf.isMarkedForDelete_ = isMarkedForDelete_;
cf.columns_ = columns_.cloneMe();
return cf;
}
@ -175,15 +178,18 @@ public final class ColumnFamily
return name_;
}
/*
/**
* We need to go through each column
* in the column family and resolve it before adding
*/
void addColumns(ColumnFamily cf)
{
for (IColumn column : cf.getAllColumns())
Map<String, IColumn> columns = cf.getColumns();
Set<String> cNames = columns.keySet();
for ( String cName : cNames )
{
addColumn(column);
addColumn(cName, columns.get(cName));
}
}
@ -193,9 +199,10 @@ public final class ColumnFamily
return columnSerializer_;
}
public void addColumn(String name)
public void createColumn(String name)
{
addColumn(columnFactory_.createColumn(name));
IColumn column = columnFactory_.createColumn(name);
addColumn(column.name(), column);
}
int getColumnCount()
@ -204,7 +211,7 @@ public final class ColumnFamily
Map<String, IColumn> columns = columns_.getColumns();
if( columns != null )
{
if(!isSuper())
if(!DatabaseDescriptor.getColumnType(name_).equals("Super"))
{
count = columns.size();
}
@ -220,26 +227,17 @@ public final class ColumnFamily
return count;
}
public boolean isSuper()
public void createColumn(String name, byte[] value)
{
return DatabaseDescriptor.getColumnType(name_).equals("Super");
IColumn column = columnFactory_.createColumn(name, value);
addColumn(column.name(), column);
}
public void addColumn(String name, byte[] value)
{
addColumn(name, value, 0);
}
public void addColumn(String name, byte[] value, long timestamp)
{
addColumn(name, value, timestamp, false);
}
public void addColumn(String name, byte[] value, long timestamp, boolean deleted)
public void createColumn(String name, byte[] value, long timestamp)
{
IColumn column = columnFactory_.createColumn(name, value, timestamp, deleted);
addColumn(column);
}
IColumn column = columnFactory_.createColumn(name, value, timestamp);
addColumn(column.name(), column);
}
void clear()
{
@ -250,30 +248,29 @@ public final class ColumnFamily
* If we find an old column that has the same name
* the ask it to resolve itself else add the new column .
*/
void addColumn(IColumn column)
void addColumn(String name, IColumn column)
{
String name = column.name();
int newSize = 0;
IColumn oldColumn = columns_.get(name);
if (oldColumn != null)
if ( oldColumn != null )
{
if (oldColumn instanceof SuperColumn)
int oldSize = oldColumn.size();
if( oldColumn.putColumn(column))
{
int oldSize = oldColumn.size();
((SuperColumn) oldColumn).putColumn(column);
size_.addAndGet(oldColumn.size() - oldSize);
// This will never be called for super column as put column always returns false.
columns_.put(name, column);
newSize = column.size();
}
else
{
if (oldColumn.timestamp() <= column.timestamp())
{
columns_.put(name, column);
size_.addAndGet(column.size());
}
newSize = oldColumn.size();
}
size_.addAndGet(newSize - oldSize);
}
else
{
size_.addAndGet(column.size());
newSize = column.size();
size_.addAndGet(newSize);
columns_.put(name, column);
}
}
@ -283,12 +280,12 @@ public final class ColumnFamily
return columns_.get( name );
}
public SortedSet<IColumn> getAllColumns()
public Collection<IColumn> getAllColumns()
{
return columns_.getSortedColumns();
}
public Map<String, IColumn> getColumns()
Map<String, IColumn> getColumns()
{
return columns_.getColumns();
}
@ -298,14 +295,17 @@ public final class ColumnFamily
columns_.remove(columnName);
}
void delete(long timestamp)
void delete()
{
markedForDeleteAt = timestamp;
if ( isMarkedForDelete_ == null )
isMarkedForDelete_ = new AtomicBoolean(true);
else
isMarkedForDelete_.set(true);
}
public boolean isMarkedForDelete()
boolean isMarkedForDelete()
{
return markedForDeleteAt > Long.MIN_VALUE;
return ( ( isMarkedForDelete_ == null ) ? false : isMarkedForDelete_.get() );
}
/*
@ -334,8 +334,28 @@ public final class ColumnFamily
*/
void repair(ColumnFamily columnFamily)
{
for (IColumn column : columnFamily.getAllColumns()) {
addColumn(column);
Map<String, IColumn> columns = columnFamily.getColumns();
Set<String> cNames = columns.keySet();
for ( String cName : cNames )
{
IColumn columnInternal = columns_.get(cName);
IColumn columnExternal = columns.get(cName);
if( columnInternal == null )
{
if(DatabaseDescriptor.getColumnFamilyType(name_).equals(ColumnFamily.getColumnType("Super")))
{
columnInternal = new SuperColumn(columnExternal.name());
columns_.put(cName, columnInternal);
}
if(DatabaseDescriptor.getColumnFamilyType(name_).equals(ColumnFamily.getColumnType("Standard")))
{
columnInternal = columnExternal;
columns_.put(cName, columnInternal);
}
}
columnInternal.repair(columnExternal);
}
}
@ -357,14 +377,14 @@ public final class ColumnFamily
IColumn columnExternal = columns.get(cName);
if( columnInternal == null )
{
cfDiff.addColumn(columnExternal);
cfDiff.addColumn(cName, columnExternal);
}
else
{
IColumn columnDiff = columnInternal.diff(columnExternal);
if(columnDiff != null)
{
cfDiff.addColumn(columnDiff);
cfDiff.addColumn(cName, columnDiff);
}
}
}
@ -403,174 +423,193 @@ public final class ColumnFamily
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("ColumnFamily(");
sb.append(name_);
sb.append(":");
sb.append(isMarkedForDelete());
sb.append(":");
Collection<IColumn> columns = getAllColumns();
sb.append(columns.size());
sb.append(":");
if (isMarkedForDelete()) {
sb.append(" -delete at " + getMarkedForDeleteAt() + "-");
for ( IColumn column : columns )
{
sb.append(column.toString());
}
sb.append(" [");
sb.append(StringUtils.join(getAllColumns(), ", "));
sb.append("])");
sb.append(":");
return sb.toString();
}
public byte[] digest()
{
Set<IColumn> columns = columns_.getSortedColumns();
byte[] xorHash = null;
byte[] xorHash = new byte[0];
byte[] tmpHash = new byte[0];
for(IColumn column : columns)
{
if(xorHash == null)
if(xorHash.length == 0)
{
xorHash = column.digest();
}
else
{
xorHash = FBUtilities.xor(xorHash, column.digest());
tmpHash = column.digest();
xorHash = FBUtilities.xor(xorHash, tmpHash);
}
}
return xorHash;
}
public long getMarkedForDeleteAt() {
return markedForDeleteAt;
}
public static class ColumnFamilySerializer implements ICompactSerializer2<ColumnFamily>
{
/*
* We are going to create indexes, and write out that information as well. The format
* of the data serialized is as follows.
*
* 1) Without indexes:
* // written by the data
* <boolean false (index is not present)>
* <column family id>
* <is marked for delete>
* <total number of columns>
* <columns data>
* <boolean true (index is present)>
*
* This part is written by the column indexer
* <size of index in bytes>
* <list of column names and their offsets relative to the first column>
*
* <size of the cf in bytes>
* <column family id>
* <is marked for delete>
* <total number of columns>
* <columns data>
*/
public void serialize(ColumnFamily columnFamily, DataOutputStream dos) throws IOException
{
Collection<IColumn> columns = columnFamily.getAllColumns();
/* write the column family id */
dos.writeUTF(columnFamily.name());
/* write if this cf is marked for delete */
dos.writeLong(columnFamily.getMarkedForDeleteAt());
/* write the size is the number of columns */
dos.writeInt(columns.size());
/* write the column data */
for ( IColumn column : columns )
{
columnFamily.getColumnSerializer().serialize(column, dos);
}
}
/*
* Use this method to create a bare bones Column Family. This column family
* does not have any of the Column information.
*/
private ColumnFamily defreezeColumnFamily(DataInputStream dis) throws IOException
{
String name = dis.readUTF();
ColumnFamily cf = new ColumnFamily(name);
cf.delete(dis.readLong());
return cf;
}
public ColumnFamily deserialize(DataInputStream dis) throws IOException
{
ColumnFamily cf = defreezeColumnFamily(dis);
int size = dis.readInt();
IColumn column = null;
for ( int i = 0; i < size; ++i )
{
column = cf.getColumnSerializer().deserialize(dis);
if(column != null)
{
cf.addColumn(column);
}
}
return cf;
}
/*
* This version of deserialize is used when we need a specific set if columns for
* a column family specified in the name cfName parameter.
*/
public ColumnFamily deserialize(DataInputStream dis, IFilter filter) throws IOException
{
ColumnFamily cf = defreezeColumnFamily(dis);
int size = dis.readInt();
IColumn column = null;
for ( int i = 0; i < size; ++i )
{
column = cf.getColumnSerializer().deserialize(dis, filter);
if(column != null)
{
cf.addColumn(column);
column = null;
if(filter.isDone())
{
break;
}
}
}
return cf;
}
/*
* Deserialize a particular column or super column or the entire columnfamily given a : seprated name
* name could be of the form cf:superColumn:column or cf:column or cf
*/
public ColumnFamily deserialize(DataInputStream dis, String name, IFilter filter) throws IOException
{
String[] names = RowMutation.getColumnAndColumnFamily(name);
String columnName = "";
if ( names.length == 1 )
return deserialize(dis, filter);
if( names.length == 2 )
columnName = names[1];
if( names.length == 3 )
columnName = names[1]+ ":" + names[2];
ColumnFamily cf = defreezeColumnFamily(dis);
/* read the number of columns */
int size = dis.readInt();
for ( int i = 0; i < size; ++i )
{
IColumn column = cf.getColumnSerializer().deserialize(dis, columnName, filter);
if ( column != null )
{
cf.addColumn(column);
break;
}
}
return cf;
}
public void skip(DataInputStream dis) throws IOException
{
throw new UnsupportedOperationException("This operation is not yet supported.");
}
}
}
class ColumnFamilySerializer implements ICompactSerializer2<ColumnFamily>
{
/*
* We are going to create indexes, and write out that information as well. The format
* of the data serialized is as follows.
*
* 1) Without indexes:
* // written by the data
* <boolean false (index is not present)>
* <column family id>
* <is marked for delete>
* <total number of columns>
* <columns data>
* <boolean true (index is present)>
*
* This part is written by the column indexer
* <size of index in bytes>
* <list of column names and their offsets relative to the first column>
*
* <size of the cf in bytes>
* <column family id>
* <is marked for delete>
* <total number of columns>
* <columns data>
*/
public void serialize(ColumnFamily columnFamily, DataOutputStream dos) throws IOException
{
Collection<IColumn> columns = columnFamily.getAllColumns();
/* write the column family id */
dos.writeUTF(columnFamily.name());
/* write if this cf is marked for delete */
dos.writeBoolean(columnFamily.isMarkedForDelete());
/* write the size is the number of columns */
dos.writeInt(columns.size());
/* write the column data */
for ( IColumn column : columns )
{
columnFamily.getColumnSerializer().serialize(column, dos);
}
}
/*
* Use this method to create a bare bones Column Family. This column family
* does not have any of the Column information.
*/
private ColumnFamily defreezeColumnFamily(DataInputStream dis) throws IOException
{
String name = dis.readUTF();
boolean delete = dis.readBoolean();
ColumnFamily cf = new ColumnFamily(name);
if ( delete )
cf.delete();
return cf;
}
/*
* This method fills the Column Family object with the column information
* from the DataInputStream. The "items" parameter tells us whether we need
* all the columns or just a subset of all the Columns that make up the
* Column Family. If "items" is -1 then we need all the columns if not we
* deserialize only as many columns as indicated by the "items" parameter.
*/
private void fillColumnFamily(ColumnFamily cf, DataInputStream dis) throws IOException
{
int size = dis.readInt();
IColumn column = null;
for ( int i = 0; i < size; ++i )
{
column = cf.getColumnSerializer().deserialize(dis);
if(column != null)
{
cf.addColumn(column.name(), column);
}
}
}
public ColumnFamily deserialize(DataInputStream dis) throws IOException
{
ColumnFamily cf = defreezeColumnFamily(dis);
if ( !cf.isMarkedForDelete() )
fillColumnFamily(cf,dis);
return cf;
}
/*
* This version of deserialize is used when we need a specific set if columns for
* a column family specified in the name cfName parameter.
*/
public ColumnFamily deserialize(DataInputStream dis, IFilter filter) throws IOException
{
ColumnFamily cf = defreezeColumnFamily(dis);
if ( !cf.isMarkedForDelete() )
{
int size = dis.readInt();
IColumn column = null;
for ( int i = 0; i < size; ++i )
{
column = cf.getColumnSerializer().deserialize(dis, filter);
if(column != null)
{
cf.addColumn(column.name(), column);
column = null;
if(filter.isDone())
{
break;
}
}
}
}
return cf;
}
/*
* Deserialize a particular column or super column or the entire columnfamily given a : seprated name
* name could be of the form cf:superColumn:column or cf:column or cf
*/
public ColumnFamily deserialize(DataInputStream dis, String name, IFilter filter) throws IOException
{
String[] names = RowMutation.getColumnAndColumnFamily(name);
String columnName = "";
if ( names.length == 1 )
return deserialize(dis, filter);
if( names.length == 2 )
columnName = names[1];
if( names.length == 3 )
columnName = names[1]+ ":" + names[2];
ColumnFamily cf = defreezeColumnFamily(dis);
if ( !cf.isMarkedForDelete() )
{
/* read the number of columns */
int size = dis.readInt();
for ( int i = 0; i < size; ++i )
{
IColumn column = cf.getColumnSerializer().deserialize(dis, columnName, filter);
if ( column != null )
{
cf.addColumn(column.name(), column);
break;
}
}
}
return cf;
}
public void skip(DataInputStream dis) throws IOException
{
throw new UnsupportedOperationException("This operation is not yet supported.");
}
}

View File

@ -18,27 +18,18 @@
package org.apache.cassandra.db;
import java.io.File;
import java.io.IOException;
import java.io.*;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.log4j.Logger;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.dht.Range;
import org.apache.cassandra.io.DataInputBuffer;
@ -47,10 +38,16 @@ import org.apache.cassandra.io.IndexHelper;
import org.apache.cassandra.io.SSTable;
import org.apache.cassandra.io.SequenceFile;
import org.apache.cassandra.net.EndPoint;
import org.apache.cassandra.net.Message;
import org.apache.cassandra.net.MessagingService;
import org.apache.cassandra.service.PartitionerType;
import org.apache.cassandra.service.StorageService;
import org.apache.cassandra.utils.BloomFilter;
import org.apache.cassandra.utils.FileUtils;
import org.apache.cassandra.utils.LogUtil;
import org.apache.log4j.Logger;
import org.apache.cassandra.io.*;
import org.apache.cassandra.utils.*;
/**
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
@ -80,7 +77,7 @@ public class ColumnFamilyStore
private ReentrantReadWriteLock lock_ = new ReentrantReadWriteLock(true);
/* Flag indicates if a compaction is in process */
private AtomicBoolean isCompacting_ = new AtomicBoolean(false);
public AtomicBoolean isCompacting_ = new AtomicBoolean(false);
ColumnFamilyStore(String table, String columnFamily) throws IOException
{
@ -130,7 +127,7 @@ public class ColumnFamilyStore
for (File file : files)
{
String filename = file.getName();
if(((file.length() == 0) || (filename.contains("-" + SSTable.temporaryFile_)) ) && (filename.contains(columnFamily_)))
if(((file.length() == 0) || (filename.indexOf("-" + SSTable.temporaryFile_) != -1) ) && (filename.indexOf(columnFamily_) != -1))
{
file.delete();
continue;
@ -139,7 +136,7 @@ public class ColumnFamilyStore
String[] tblCfName = getTableAndColumnFamilyName(filename);
if (tblCfName[0].equals(table_)
&& tblCfName[1].equals(columnFamily_)
&& filename.contains("-Data.db"))
&& filename.indexOf("-Data.db") != -1)
{
ssTables.add(file.getAbsoluteFile());
}
@ -177,7 +174,7 @@ public class ColumnFamilyStore
* disk and the total space oocupied by the data files
* associated with this Column Family.
*/
public String cfStats(String newLineSeparator)
public String cfStats(String newLineSeparator, java.text.DecimalFormat df)
{
StringBuilder sb = new StringBuilder();
/*
@ -260,7 +257,7 @@ public class ColumnFamilyStore
if( ranges != null)
futurePtr = MinorCompactionManager.instance().submit(ColumnFamilyStore.this, ranges, target, fileList);
else
MinorCompactionManager.instance().submitMajor(ColumnFamilyStore.this, skip);
MinorCompactionManager.instance().submitMajor(ColumnFamilyStore.this, ranges, skip);
boolean result = true;
try
@ -333,7 +330,8 @@ public class ColumnFamilyStore
{
// Psuedo increment so that we do not generate consecutive numbers
fileIndexGenerator_.incrementAndGet();
return table_ + "-" + columnFamily_ + "-" + fileIndexGenerator_.incrementAndGet();
String name = table_ + "-" + columnFamily_ + "-" + fileIndexGenerator_.incrementAndGet();
return name;
}
/*
@ -343,7 +341,8 @@ public class ColumnFamilyStore
{
// Psuedo increment so that we do not generate consecutive numbers
fileIndexGenerator_.incrementAndGet();
return table_ + "-" + columnFamily_ + "-" + SSTable.temporaryFile_ + "-" + fileIndexGenerator_.incrementAndGet();
String name = table_ + "-" + columnFamily_ + "-" + SSTable.temporaryFile_ + "-" + fileIndexGenerator_.incrementAndGet() ;
return name;
}
/*
@ -364,8 +363,9 @@ public class ColumnFamilyStore
lowestIndex = getIndexFromFileName(files.get(0));
index = lowestIndex + 1 ;
return table_ + "-" + columnFamily_ + "-" + SSTable.temporaryFile_ + "-" + index;
String name = table_ + "-" + columnFamily_ + "-" + SSTable.temporaryFile_ + "-" + index ;
return name;
}
@ -382,6 +382,14 @@ public class ColumnFamilyStore
memtable_.get().put(key, columnFamily, cLogCtx);
}
/*
* This version is used when we forceflush.
*/
void switchMemtable() throws IOException
{
memtable_.set( new Memtable(table_, columnFamily_) );
}
/*
* This version is used only on start up when we are recovering from logs.
* In the future we may want to parellelize the log processing for a table
@ -394,14 +402,14 @@ public class ColumnFamilyStore
binaryMemtable_.get().put(key, buffer);
}
void forceFlush() throws IOException
void forceFlush(boolean fRecovery) throws IOException
{
//MemtableManager.instance().submit(getColumnFamilyName(), memtable_.get() , CommitLog.CommitLogContext.NULL);
//memtable_.get().flush(true, CommitLog.CommitLogContext.NULL);
memtable_.get().forceflush(this);
memtable_.get().forceflush(this, fRecovery);
}
void forceFlushBinary()
void forceFlushBinary() throws IOException
{
BinaryMemtableManager.instance().submit(getColumnFamilyName(), binaryMemtable_.get());
//binaryMemtable_.get().flush(true);
@ -430,36 +438,66 @@ public class ColumnFamilyStore
binaryMemtable_.get().put(key, buffer);
}
public ColumnFamily getColumnFamily(String key, String columnFamilyColumn, IFilter filter) throws IOException
{
List<ColumnFamily> columnFamilies = getColumnFamilies(key, columnFamilyColumn, filter);
return resolveAndRemoveDeleted(columnFamilies);
}
/**
*
* Get the column family in the most efficient order.
* 1. Memtable
* 2. Sorted list of files
*/
List<ColumnFamily> getColumnFamilies(String key, String columnFamilyColumn, IFilter filter) throws IOException
public ColumnFamily getColumnFamily(String key, String cf, IFilter filter) throws IOException
{
List<ColumnFamily> columnFamilies1 = new ArrayList<ColumnFamily>();
List<ColumnFamily> columnFamilies = new ArrayList<ColumnFamily>();
ColumnFamily columnFamily = null;
long start = System.currentTimeMillis();
/* Get the ColumnFamily from Memtable */
getColumnFamilyFromCurrentMemtable(key, columnFamilyColumn, filter, columnFamilies1);
if (columnFamilies1.size() == 0 || !filter.isDone())
getColumnFamilyFromCurrentMemtable(key, cf, filter, columnFamilies);
if(columnFamilies.size() != 0)
{
/* Check if MemtableManager has any historical information */
MemtableManager.instance().getColumnFamily(key, columnFamily_, columnFamilyColumn, filter, columnFamilies1);
if(filter.isDone())
return columnFamilies.get(0);
}
List<ColumnFamily> columnFamilies = columnFamilies1;
if (columnFamilies.size() == 0 || !filter.isDone())
/* Check if MemtableManager has any historical information */
MemtableManager.instance().getColumnFamily(key, columnFamily_, cf, filter, columnFamilies);
if(columnFamilies.size() != 0)
{
long start = System.currentTimeMillis();
getColumnFamilyFromDisk(key, columnFamilyColumn, columnFamilies, filter);
logger_.debug("DISK TIME: " + (System.currentTimeMillis() - start) + " ms.");
columnFamily = resolve(columnFamilies);
if(filter.isDone())
return columnFamily;
columnFamilies.clear();
columnFamilies.add(columnFamily);
}
return columnFamilies;
getColumnFamilyFromDisk(key, cf, columnFamilies, filter);
logger_.debug("DISK TIME: " + (System.currentTimeMillis() - start)
+ " ms.");
columnFamily = resolve(columnFamilies);
return columnFamily;
}
public ColumnFamily getColumnFamilyFromMemory(String key, String cf, IFilter filter)
{
List<ColumnFamily> columnFamilies = new ArrayList<ColumnFamily>();
ColumnFamily columnFamily = null;
long start = System.currentTimeMillis();
/* Get the ColumnFamily from Memtable */
getColumnFamilyFromCurrentMemtable(key, cf, filter, columnFamilies);
if(columnFamilies.size() != 0)
{
if(filter.isDone())
return columnFamilies.get(0);
}
/* Check if MemtableManager has any historical information */
MemtableManager.instance().getColumnFamily(key, columnFamily_, cf, filter, columnFamilies);
if(columnFamilies.size() != 0)
{
columnFamily = resolve(columnFamilies);
if(filter.isDone())
return columnFamily;
columnFamilies.clear();
columnFamilies.add(columnFamily);
}
columnFamily = resolve(columnFamilies);
return columnFamily;
}
/**
@ -499,14 +537,33 @@ public class ColumnFamilyStore
long start = System.currentTimeMillis();
if (columnFamily != null)
{
/*
* TODO
* By using the filter before removing deleted columns
* we have a efficient implementation of timefilter
* but for count filter this can return wrong results
* we need to take care of that later.
*/
/* suppress columns marked for delete */
Map<String, IColumn> columns = columnFamily.getColumns();
Set<String> cNames = columns.keySet();
for (String cName : cNames)
{
IColumn column = columns.get(cName);
if (column.isMarkedForDelete())
columns.remove(cName);
}
columnFamilies.add(columnFamily);
if(filter.isDone())
{
break;
}
}
logger_.debug("DISK Data structure population TIME: " + (System.currentTimeMillis() - start) + " ms.");
logger_.debug("DISK Data structure population TIME: " + (System.currentTimeMillis() - start)
+ " ms.");
}
files.clear();
}
@ -520,11 +577,12 @@ public class ColumnFamilyStore
if (bufIn.getLength() == 0)
return null;
start = System.currentTimeMillis();
ColumnFamily columnFamily = ColumnFamily.serializer().deserialize(bufIn, cf, filter);
ColumnFamily columnFamily = null;
columnFamily = ColumnFamily.serializer().deserialize(bufIn, cf, filter);
logger_.debug("DISK Deserialize TIME: " + (System.currentTimeMillis() - start) + " ms.");
if (columnFamily == null)
return null;
return columnFamily;
return columnFamily;
return (!columnFamily.isMarkedForDelete()) ? columnFamily : null;
}
private void getColumnFamilyFromCurrentMemtable(String key, String cf, IFilter filter, List<ColumnFamily> columnFamilies)
@ -533,66 +591,20 @@ public class ColumnFamilyStore
ColumnFamily columnFamily = memtable_.get().get(key, cf, filter);
if (columnFamily != null)
{
columnFamilies.add(columnFamily);
if (!columnFamily.isMarkedForDelete())
columnFamilies.add(columnFamily);
}
}
/** merge all columnFamilies into a single instance, with only the newest versions of columns preserved. */
static ColumnFamily resolve(List<ColumnFamily> columnFamilies)
private ColumnFamily resolve(List<ColumnFamily> columnFamilies)
{
int size = columnFamilies.size();
if (size == 0)
return null;
// start from nothing so that we don't include potential deleted columns from the first instance
String cfname = columnFamilies.get(0).name();
ColumnFamily cf = new ColumnFamily(cfname);
// merge
for (ColumnFamily cf2 : columnFamilies)
return null;
ColumnFamily cf = columnFamilies.get(0);
for ( int i = 1; i < size ; ++i )
{
assert cf.name().equals(cf2.name());
cf.addColumns(cf2);
cf.delete(Math.max(cf.getMarkedForDeleteAt(), cf2.getMarkedForDeleteAt()));
}
return cf;
}
/** like resolve, but leaves the resolved CF as the only item in the list */
private static void merge(List<ColumnFamily> columnFamilies)
{
ColumnFamily cf = resolve(columnFamilies);
columnFamilies.clear();
columnFamilies.add(cf);
}
private static ColumnFamily resolveAndRemoveDeleted(List<ColumnFamily> columnFamilies) {
ColumnFamily cf = resolve(columnFamilies);
return removeDeleted(cf);
}
static ColumnFamily removeDeleted(ColumnFamily cf) {
if (cf == null) {
return null;
}
for (String cname : new ArrayList<String>(cf.getColumns().keySet())) {
IColumn c = cf.getColumns().get(cname);
if (c instanceof SuperColumn) {
long min_timestamp = Math.max(c.getMarkedForDeleteAt(), cf.getMarkedForDeleteAt());
// don't operate directly on the supercolumn, it could be the one in the memtable
cf.remove(cname);
IColumn sc = new SuperColumn(cname);
for (IColumn subColumn : c.getSubColumns()) {
if (!subColumn.isMarkedForDelete() && subColumn.timestamp() >= min_timestamp) {
sc.addColumn(subColumn.name(), subColumn);
}
}
if (sc.getSubColumns().size() > 0) {
cf.addColumn(sc);
}
} else if (c.isMarkedForDelete() || c.timestamp() < cf.getMarkedForDeleteAt()) {
cf.remove(cname);
}
cf.addColumns(columnFamilies.get(i));
}
return cf;
}
@ -605,7 +617,19 @@ public class ColumnFamilyStore
*/
void applyNow(String key, ColumnFamily columnFamily) throws IOException
{
memtable_.get().putOnRecovery(key, columnFamily);
if (!columnFamily.isMarkedForDelete())
memtable_.get().putOnRecovery(key, columnFamily);
}
/*
* Delete doesn't mean we can blindly delete. We need to write this to disk
* as being marked for delete. This is to prevent a previous value from
* resuscitating a column family that has been deleted.
*/
void delete(String key, ColumnFamily columnFamily)
throws IOException
{
memtable_.get().remove(key, columnFamily);
}
/*
@ -629,7 +653,7 @@ public class ColumnFamilyStore
* param @ filename - filename just flushed to disk
* param @ bf - bloom filter which indicates the keys that are in this file.
*/
void storeLocation(String filename, BloomFilter bf)
void storeLocation(String filename, BloomFilter bf) throws IOException
{
boolean doCompaction = false;
int ssTableSize = 0;
@ -664,7 +688,7 @@ public class ColumnFamilyStore
}
}
PriorityQueue<FileStruct> initializePriorityQueue(List<String> files, List<Range> ranges, int minBufferSize)
PriorityQueue<FileStruct> initializePriorityQueue(List<String> files, List<Range> ranges, int minBufferSize) throws IOException
{
PriorityQueue<FileStruct> pq = new PriorityQueue<FileStruct>();
if (files.size() > 1 || (ranges != null && files.size() > 0))
@ -675,9 +699,13 @@ public class ColumnFamilyStore
{
try
{
fs = new FileStruct(SequenceFile.bufferedReader(file, bufferSize));
fs.getNextKey();
if(fs.isExhausted())
fs = new FileStruct();
fs.bufIn_ = new DataInputBuffer();
fs.bufOut_ = new DataOutputBuffer();
fs.reader_ = SequenceFile.bufferedReader(file, bufferSize);
fs.key_ = null;
fs = getNextKey(fs);
if(fs == null)
continue;
pq.add(fs);
}
@ -686,16 +714,17 @@ public class ColumnFamilyStore
ex.printStackTrace();
try
{
if (fs != null)
if(fs != null)
{
fs.close();
fs.reader_.close();
}
}
catch(Exception e)
{
logger_.warn("Unable to close file :" + file);
}
}
continue;
}
}
}
return pq;
@ -747,7 +776,7 @@ public class ColumnFamilyStore
/*
* Break the files into buckets and then compact.
*/
void doCompaction()
void doCompaction() throws IOException
{
isCompacting_.set(true);
List<String> files = new ArrayList<String>(ssTables_);
@ -789,6 +818,7 @@ public class ColumnFamilyStore
{
isCompacting_.set(false);
}
return;
}
void doMajorCompaction(long skip) throws IOException
@ -796,13 +826,18 @@ public class ColumnFamilyStore
doMajorCompactionInternal( skip );
}
void doMajorCompaction() throws IOException
{
doMajorCompactionInternal( 0 );
}
/*
* Compact all the files irrespective of the size.
* skip : is the ammount in Gb of the files to be skipped
* all files greater than skip GB are skipped for this compaction.
* Except if skip is 0 , in that case this is ignored and all files are taken.
*/
void doMajorCompactionInternal(long skip)
void doMajorCompactionInternal(long skip) throws IOException
{
isCompacting_.set(true);
List<String> filesInternal = new ArrayList<String>(ssTables_);
@ -835,6 +870,7 @@ public class ColumnFamilyStore
{
isCompacting_.set(false);
}
return ;
}
/*
@ -872,14 +908,41 @@ public class ColumnFamilyStore
return maxFile;
}
boolean doAntiCompaction(List<Range> ranges, EndPoint target, List<String> fileList)
Range getMaxRange( List<Range> ranges )
{
Range maxRange = new Range( BigInteger.ZERO, BigInteger.ZERO );
for( Range range : ranges)
{
if( range.left().compareTo(maxRange.left()) > 0 )
{
maxRange = range;
}
}
return maxRange;
}
boolean isLoopAround ( List<Range> ranges )
{
boolean isLoop = false;
for( Range range : ranges)
{
if( range.left().compareTo(range.right()) > 0 )
{
isLoop = true;
break;
}
}
return isLoop;
}
boolean doAntiCompaction(List<Range> ranges, EndPoint target, List<String> fileList) throws IOException
{
isCompacting_.set(true);
List<String> files = new ArrayList<String>(ssTables_);
boolean result = true;
try
{
result = doFileAntiCompaction(files, ranges, target, fileList, null);
result = doFileAntiCompaction(files, ranges, target, bufSize_, fileList, null);
}
catch ( Exception ex)
{
@ -893,6 +956,38 @@ public class ColumnFamilyStore
}
/*
* Read the next key from the data file , this fn will skip teh block index
* and read teh next available key into the filestruct that is passed.
* If it cannot read or a end of file is reached it will return null.
*/
FileStruct getNextKey(FileStruct filestruct) throws IOException
{
filestruct.bufOut_.reset();
if (filestruct.reader_.isEOF())
{
filestruct.reader_.close();
return null;
}
long bytesread = filestruct.reader_.next(filestruct.bufOut_);
if (bytesread == -1)
{
filestruct.reader_.close();
return null;
}
filestruct.bufIn_.reset(filestruct.bufOut_.getData(), filestruct.bufOut_.getLength());
filestruct.key_ = filestruct.bufIn_.readUTF();
/* If the key we read is the Block Index Key then we are done reading the keys so exit */
if ( filestruct.key_.equals(SSTable.blockIndexKey_) )
{
filestruct.reader_.close();
return null;
}
return filestruct;
}
void forceCleanup()
{
MinorCompactionManager.instance().submitCleanup(ColumnFamilyStore.this);
@ -903,7 +998,7 @@ public class ColumnFamilyStore
* and only keeps keys that this node is responsible for.
* @throws IOException
*/
void doCleanupCompaction()
void doCleanupCompaction() throws IOException
{
isCompacting_.set(true);
List<String> files = new ArrayList<String>(ssTables_);
@ -937,7 +1032,7 @@ public class ColumnFamilyStore
Map<EndPoint, List<Range>> endPointtoRangeMap = StorageService.instance().constructEndPointToRangesMap();
myRanges = endPointtoRangeMap.get(StorageService.getLocalStorageEndPoint());
List<BloomFilter> compactedBloomFilters = new ArrayList<BloomFilter>();
doFileAntiCompaction(files, myRanges, null, newFiles, compactedBloomFilters);
doFileAntiCompaction(files, myRanges, null, bufSize_, newFiles, compactedBloomFilters);
logger_.debug("Original file : " + file + " of size " + new File(file).length());
lock_.writeLock().lock();
try
@ -968,11 +1063,12 @@ public class ColumnFamilyStore
* @param files
* @param ranges
* @param target
* @param minBufferSize
* @param fileList
* @return
* @throws IOException
*/
boolean doFileAntiCompaction(List<String> files, List<Range> ranges, EndPoint target, List<String> fileList, List<BloomFilter> compactedBloomFilters)
boolean doFileAntiCompaction(List<String> files, List<Range> ranges, EndPoint target, int minBufferSize, List<String> fileList, List<BloomFilter> compactedBloomFilters) throws IOException
{
boolean result = false;
long startTime = System.currentTimeMillis();
@ -998,7 +1094,7 @@ public class ColumnFamilyStore
+ expectedRangeFileSize + " is greater than the safe limit of the disk space available.");
return result;
}
PriorityQueue<FileStruct> pq = initializePriorityQueue(files, ranges, ColumnFamilyStore.bufSize_);
PriorityQueue<FileStruct> pq = initializePriorityQueue(files, ranges, minBufferSize);
if (pq.size() > 0)
{
mergedFileName = getTempFileName();
@ -1021,11 +1117,11 @@ public class ColumnFamilyStore
fs = pq.poll();
}
if (fs != null
&& (lastkey == null || lastkey.compareTo(fs.getKey()) == 0))
&& (lastkey == null || lastkey.compareTo(fs.key_) == 0))
{
// The keys are the same so we need to add this to the
// ldfs list
lastkey = fs.getKey();
lastkey = fs.key_;
lfs.add(fs);
}
else
@ -1040,30 +1136,38 @@ public class ColumnFamilyStore
try
{
/* read the length although we don't need it */
filestruct.getBufIn().readInt();
filestruct.bufIn_.readInt();
// Skip the Index
IndexHelper.skipBloomFilterAndIndex(filestruct.getBufIn());
IndexHelper.skipBloomFilterAndIndex(filestruct.bufIn_);
// We want to add only 2 and resolve them right there in order to save on memory footprint
if(columnFamilies.size() > 1)
{
// Now merge the 2 column families
merge(columnFamilies);
columnFamily = resolve(columnFamilies);
columnFamilies.clear();
if( columnFamily != null)
{
// add the merged columnfamily back to the list
columnFamilies.add(columnFamily);
}
}
// deserialize into column families
columnFamilies.add(ColumnFamily.serializer().deserialize(filestruct.getBufIn()));
columnFamilies.add(ColumnFamily.serializer().deserialize(filestruct.bufIn_));
}
catch ( Exception ex)
{
logger_.warn(LogUtil.throwableToString(ex));
}
continue;
}
}
// Now after merging all crap append to the sstable
columnFamily = resolveAndRemoveDeleted(columnFamilies);
columnFamily = resolve(columnFamilies);
columnFamilies.clear();
if( columnFamily != null )
{
/* serialize the cf with column indexes */
ColumnFamily.serializerWithIndexes().serialize(columnFamily, bufOut);
ColumnFamily.serializer2().serialize(columnFamily, bufOut);
}
}
else
@ -1072,17 +1176,17 @@ public class ColumnFamilyStore
try
{
/* read the length although we don't need it */
int size = filestruct.getBufIn().readInt();
bufOut.write(filestruct.getBufIn(), size);
int size = filestruct.bufIn_.readInt();
bufOut.write(filestruct.bufIn_, size);
}
catch ( Exception ex)
{
logger_.warn(LogUtil.throwableToString(ex));
filestruct.close();
filestruct.reader_.close();
continue;
}
}
if ( Range.isKeyInRanges(lastkey, ranges) )
if ( Range.isKeyInRanges(ranges, lastkey) )
{
if(ssTableRange == null )
{
@ -1106,28 +1210,28 @@ public class ColumnFamilyStore
{
try
{
filestruct.getNextKey();
if (filestruct.isExhausted())
filestruct = getNextKey ( filestruct );
if(filestruct == null)
{
continue;
}
/* keep on looping until we find a key in the range */
while ( !Range.isKeyInRanges(filestruct.getKey(), ranges) )
while ( !Range.isKeyInRanges(ranges, filestruct.key_ ) )
{
filestruct.getNextKey();
if (filestruct.isExhausted())
filestruct = getNextKey ( filestruct );
if(filestruct == null)
{
break;
}
/* check if we need to continue , if we are done with ranges empty the queue and close all file handles and exit */
//if( !isLoop && StorageService.token(filestruct.key).compareTo(maxRange.right()) > 0 && !filestruct.key.equals(""))
//if( !isLoop && StorageService.hash(filestruct.key).compareTo(maxRange.right()) > 0 && !filestruct.key.equals(""))
//{
//filestruct.reader.close();
//filestruct = null;
//break;
//}
}
if (!filestruct.isExhausted())
if ( filestruct != null)
{
pq.add(filestruct);
}
@ -1139,8 +1243,9 @@ public class ColumnFamilyStore
// in any case we have read as far as possible from it
// and it will be deleted after compaction.
logger_.warn(LogUtil.throwableToString(ex));
filestruct.close();
}
filestruct.reader_.close();
continue;
}
}
lfs.clear();
lastkey = null;
@ -1173,10 +1278,39 @@ public class ColumnFamilyStore
+ totalBytesWritten + " Total keys read ..." + totalkeysRead);
return result;
}
private void doFill(BloomFilter bf, String decoratedKey)
private void doWrite(SSTable ssTable, String key, DataOutputBuffer bufOut) throws IOException
{
bf.fill(StorageService.getPartitioner().undecorateKey(decoratedKey));
PartitionerType pType = StorageService.getPartitionerType();
switch ( pType )
{
case OPHF:
ssTable.append(key, bufOut);
break;
default:
String[] peices = key.split(":");
key = peices[1];
BigInteger hash = new BigInteger(peices[0]);
ssTable.append(key, hash, bufOut);
break;
}
}
private void doFill(BloomFilter bf, String key)
{
PartitionerType pType = StorageService.getPartitionerType();
switch ( pType )
{
case OPHF:
bf.fill(key);
break;
default:
String[] peices = key.split(":");
bf.fill(peices[1]);
break;
}
}
/*
@ -1190,7 +1324,7 @@ public class ColumnFamilyStore
* to get the latest data.
*
*/
void doFileCompaction(List<String> files, int minBufferSize)
void doFileCompaction(List<String> files, int minBufferSize) throws IOException
{
String newfile = null;
long startTime = System.currentTimeMillis();
@ -1234,11 +1368,11 @@ public class ColumnFamilyStore
fs = pq.poll();
}
if (fs != null
&& (lastkey == null || lastkey.compareTo(fs.getKey()) == 0))
&& (lastkey == null || lastkey.compareTo(fs.key_) == 0))
{
// The keys are the same so we need to add this to the
// ldfs list
lastkey = fs.getKey();
lastkey = fs.key_;
lfs.add(fs);
}
else
@ -1253,29 +1387,37 @@ public class ColumnFamilyStore
try
{
/* read the length although we don't need it */
filestruct.getBufIn().readInt();
filestruct.bufIn_.readInt();
// Skip the Index
IndexHelper.skipBloomFilterAndIndex(filestruct.getBufIn());
IndexHelper.skipBloomFilterAndIndex(filestruct.bufIn_);
// We want to add only 2 and resolve them right there in order to save on memory footprint
if(columnFamilies.size() > 1)
{
merge(columnFamilies);
// Now merge the 2 column families
columnFamily = resolve(columnFamilies);
columnFamilies.clear();
if( columnFamily != null)
{
// add the merged columnfamily back to the list
columnFamilies.add(columnFamily);
}
}
// deserialize into column families
columnFamilies.add(ColumnFamily.serializer().deserialize(filestruct.getBufIn()));
columnFamilies.add(ColumnFamily.serializer().deserialize(filestruct.bufIn_));
}
catch ( Exception ex)
{
logger_.warn("error in filecompaction", ex);
}
{
continue;
}
}
// Now after merging all crap append to the sstable
columnFamily = resolveAndRemoveDeleted(columnFamilies);
columnFamily = resolve(columnFamilies);
columnFamilies.clear();
if( columnFamily != null )
{
/* serialize the cf with column indexes */
ColumnFamily.serializerWithIndexes().serialize(columnFamily, bufOut);
ColumnFamily.serializer2().serialize(columnFamily, bufOut);
}
}
else
@ -1284,23 +1426,24 @@ public class ColumnFamilyStore
try
{
/* read the length although we don't need it */
int size = filestruct.getBufIn().readInt();
bufOut.write(filestruct.getBufIn(), size);
int size = filestruct.bufIn_.readInt();
bufOut.write(filestruct.bufIn_, size);
}
catch ( Exception ex)
{
ex.printStackTrace();
filestruct.close();
filestruct.reader_.close();
continue;
}
}
if ( ssTable == null )
{
ssTable = new SSTable(compactionFileLocation, mergedFileName);
PartitionerType pType = StorageService.getPartitionerType();
ssTable = new SSTable(compactionFileLocation, mergedFileName, pType);
}
ssTable.append(lastkey, bufOut);
doWrite(ssTable, lastkey, bufOut);
/* Fill the bloom filter with the key */
doFill(compactedBloomFilter, lastkey);
totalkeysWritten++;
@ -1308,8 +1451,8 @@ public class ColumnFamilyStore
{
try
{
filestruct.getNextKey();
if (filestruct.isExhausted())
filestruct = getNextKey(filestruct);
if(filestruct == null)
{
continue;
}
@ -1321,8 +1464,9 @@ public class ColumnFamilyStore
// Ignore the exception as it might be a corrupted file
// in any case we have read as far as possible from it
// and it will be deleted after compaction.
filestruct.close();
}
filestruct.reader_.close();
continue;
}
}
lfs.clear();
lastkey = null;
@ -1373,25 +1517,6 @@ public class ColumnFamilyStore
logger_.debug("Total bytes Read for compaction ..." + totalBytesRead);
logger_.debug("Total bytes written for compaction ..."
+ totalBytesWritten + " Total keys read ..." + totalkeysRead);
}
public boolean isSuper()
{
return DatabaseDescriptor.getColumnType(getColumnFamilyName()).equals("Super");
}
public void flushMemtableOnRecovery() throws IOException
{
memtable_.get().flushOnRecovery();
}
public Object getMemtable()
{
return memtable_.get();
}
public Set<String> getSSTableFilenames()
{
return Collections.unmodifiableSet(ssTables_);
return;
}
}

View File

@ -21,18 +21,22 @@ package org.apache.cassandra.db;
import java.io.*;
import java.util.*;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.io.DataInputBuffer;
import org.apache.cassandra.io.DataOutputBuffer;
import org.apache.cassandra.io.IFileReader;
import org.apache.cassandra.io.IFileWriter;
import org.apache.cassandra.io.SequenceFile;
import org.apache.cassandra.service.StorageService;
import org.apache.cassandra.utils.FBUtilities;
import org.apache.cassandra.utils.FileUtils;
import org.apache.cassandra.utils.LogUtil;
import org.apache.log4j.Logger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.cassandra.io.*;
import org.apache.cassandra.utils.*;
/*
* Commit Log tracks every write operation into the system. The aim
@ -372,7 +376,7 @@ class CommitLog
try
{
Row row = Row.serializer().deserialize(bufIn);
Map<String, ColumnFamily> columnFamilies = new HashMap<String, ColumnFamily>(row.getColumnFamilyMap());
Map<String, ColumnFamily> columnFamilies = new HashMap<String, ColumnFamily>(row.getColumnFamilies());
/* remove column families that have already been flushed */
Set<String> cNames = columnFamilies.keySet();
@ -419,7 +423,7 @@ class CommitLog
*/
private void updateHeader(Row row) throws IOException
{
Map<String, ColumnFamily> columnFamilies = row.getColumnFamilyMap();
Map<String, ColumnFamily> columnFamilies = row.getColumnFamilies();
Table table = Table.open(table_);
Set<String> cNames = columnFamilies.keySet();
for ( String cName : cNames )
@ -626,6 +630,9 @@ class CommitLog
public static void main(String[] args) throws Throwable
{
LogUtil.init();
// the return value is not used in this case
DatabaseDescriptor.init();
File logDir = new File(DatabaseDescriptor.getLogFileLocation());
File[] files = logDir.listFiles();

View File

@ -21,6 +21,7 @@ import java.io.DataInputStream;
import java.io.IOException;
import java.util.Collection;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.io.DataInputBuffer;
import org.apache.cassandra.io.SSTable;
@ -36,19 +37,19 @@ public class CountFilter implements IFilter
{
private long countLimit_;
private boolean isDone_;
CountFilter(int countLimit)
{
countLimit_ = countLimit;
countLimit_ = countLimit;
isDone_ = false;
}
public ColumnFamily filter(String cfNameParam, ColumnFamily columnFamily)
{
String[] values = RowMutation.getColumnAndColumnFamily(cfNameParam);
if ( columnFamily == null )
return columnFamily;
String cfName = columnFamily.name();
ColumnFamily filteredCf = new ColumnFamily(cfName);
if( countLimit_ <= 0 )
@ -61,7 +62,7 @@ public class CountFilter implements IFilter
Collection<IColumn> columns = columnFamily.getAllColumns();
for(IColumn column : columns)
{
filteredCf.addColumn(column);
filteredCf.addColumn(column.name(), column);
countLimit_--;
if( countLimit_ <= 0 )
{
@ -70,14 +71,14 @@ public class CountFilter implements IFilter
}
}
}
else if(values.length == 2 && columnFamily.isSuper())
else if(values.length == 2 && DatabaseDescriptor.getColumnType(cfName).equals("Super"))
{
Collection<IColumn> columns = columnFamily.getAllColumns();
for(IColumn column : columns)
{
SuperColumn superColumn = (SuperColumn)column;
SuperColumn filteredSuperColumn = new SuperColumn(superColumn.name());
filteredCf.addColumn(filteredSuperColumn);
filteredCf.addColumn(filteredSuperColumn.name(), filteredSuperColumn);
Collection<IColumn> subColumns = superColumn.getSubColumns();
for(IColumn subColumn : subColumns)
{
@ -90,14 +91,14 @@ public class CountFilter implements IFilter
}
}
}
}
else
}
else
{
throw new UnsupportedOperationException();
}
return filteredCf;
}
public IColumn filter(IColumn column, DataInputStream dis) throws IOException
{
countLimit_--;
@ -107,7 +108,7 @@ public class CountFilter implements IFilter
}
return column;
}
public boolean isDone()
{
return isDone_;

View File

@ -18,18 +18,27 @@
package org.apache.cassandra.db;
import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.net.InetAddress;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.dht.IPartitioner;
import org.apache.cassandra.dht.Token;
import org.apache.cassandra.io.DataOutputBuffer;
import org.apache.cassandra.io.IFileWriter;
import org.apache.cassandra.io.SequenceFile;
import org.apache.cassandra.service.StorageService;
import org.apache.cassandra.utils.BasicUtilities;
import org.apache.cassandra.utils.FBUtilities;
import org.apache.cassandra.utils.GuidGenerator;
import org.apache.cassandra.utils.HashingSchemes;
/**
@ -61,23 +70,23 @@ public class DBManager
public static class StorageMetadata
{
private Token myToken;
private BigInteger storageId_;
private int generation_;
StorageMetadata(Token storageId, int generation)
StorageMetadata(BigInteger storageId, int generation)
{
myToken = storageId;
storageId_ = storageId;
generation_ = generation;
}
public Token getStorageId()
public BigInteger getStorageId()
{
return myToken;
return storageId_;
}
public void setStorageId(Token storageId)
public void setStorageId(BigInteger storageId)
{
myToken = storageId;
storageId_ = storageId;
}
public int getGeneration()
@ -88,7 +97,10 @@ public class DBManager
public DBManager() throws Throwable
{
Set<String> tables = DatabaseDescriptor.getTableToColumnFamilyMap().keySet();
/* Read the configuration file */
Map<String, Map<String, CFMetaData>> tableToColumnFamilyMap = DatabaseDescriptor.init();
storeMetadata(tableToColumnFamilyMap);
Set<String> tables = tableToColumnFamilyMap.keySet();
for (String table : tables)
{
@ -100,6 +112,47 @@ public class DBManager
recoveryMgr.doRecovery();
}
/*
* Create the metadata tables. This table has information about
* the table name and the column families that make up the table.
* Each column family also has an associated ID which is an int.
*/
private static void storeMetadata(Map<String, Map<String, CFMetaData>> tableToColumnFamilyMap) throws Throwable
{
AtomicInteger idGenerator = new AtomicInteger(0);
Set<String> tables = tableToColumnFamilyMap.keySet();
for ( String table : tables )
{
Table.TableMetadata tmetadata = Table.TableMetadata.instance();
if ( tmetadata.isEmpty() )
{
tmetadata = Table.TableMetadata.instance();
/* Column families associated with this table */
Map<String, CFMetaData> columnFamilies = tableToColumnFamilyMap.get(table);
for (String columnFamily : columnFamilies.keySet())
{
tmetadata.add(columnFamily, idGenerator.getAndIncrement(), DatabaseDescriptor.getColumnType(columnFamily));
}
/*
* Here we add all the system related column families.
*/
/* Add the TableMetadata column family to this map. */
tmetadata.add(Table.TableMetadata.cfName_, idGenerator.getAndIncrement());
/* Add the LocationInfo column family to this map. */
tmetadata.add(SystemTable.cfName_, idGenerator.getAndIncrement());
/* Add the recycle column family to this map. */
tmetadata.add(Table.recycleBin_, idGenerator.getAndIncrement());
/* Add the Hints column family to this map. */
tmetadata.add(Table.hints_, idGenerator.getAndIncrement(), ColumnFamily.getColumnType("Super"));
tmetadata.apply();
idGenerator.set(0);
}
}
}
/*
* This method reads the system table and retrieves the metadata
* associated with this storage instance. Currently we store the
@ -114,17 +167,22 @@ public class DBManager
SystemTable sysTable = SystemTable.openSystemTable(SystemTable.name_);
Row row = sysTable.get(FBUtilities.getHostName());
IPartitioner p = StorageService.getPartitioner();
Random random = new Random();
if ( row == null )
{
Token token = p.getDefaultToken();
/* Generate a token for this Storage node */
String guid = GuidGenerator.guid();
BigInteger token = StorageService.hash(guid);
if ( token.signum() == -1 )
token = token.multiply(BigInteger.valueOf(-1L));
int generation = 1;
String key = FBUtilities.getHostName();
row = new Row(key);
ColumnFamily cf = new ColumnFamily(SystemTable.cfName_);
cf.addColumn(new Column(SystemTable.token_, p.getTokenFactory().toByteArray(token)));
cf.addColumn(new Column(SystemTable.generation_, BasicUtilities.intToByteArray(generation)) );
cf.addColumn(SystemTable.token_, new Column(SystemTable.token_, token.toByteArray()) );
cf.addColumn(SystemTable.generation_, new Column(SystemTable.generation_, BasicUtilities.intToByteArray(generation)) );
row.addColumnFamily(cf);
sysTable.apply(row);
storageMetadata = new StorageMetadata( token, generation);
@ -132,22 +190,22 @@ public class DBManager
else
{
/* we crashed and came back up need to bump generation # */
Map<String, ColumnFamily> columnFamilies = row.getColumnFamilyMap();
Map<String, ColumnFamily> columnFamilies = row.getColumnFamilies();
Set<String> cfNames = columnFamilies.keySet();
for ( String cfName : cfNames )
{
ColumnFamily columnFamily = columnFamilies.get(cfName);
IColumn tokenColumn = columnFamily.getColumn(SystemTable.token_);
Token token = p.getTokenFactory().fromByteArray(tokenColumn.value());
IColumn token = columnFamily.getColumn(SystemTable.token_);
BigInteger bi = new BigInteger( token.value() );
IColumn generation = columnFamily.getColumn(SystemTable.generation_);
int gen = BasicUtilities.byteArrayToInt(generation.value()) + 1;
Column generation2 = new Column("Generation", BasicUtilities.intToByteArray(gen), generation.timestamp() + 1);
columnFamily.addColumn(generation2);
storageMetadata = new StorageMetadata(token, gen);
columnFamily.addColumn("Generation", generation2);
storageMetadata = new StorageMetadata( bi, gen );
break;
}
sysTable.reset(row);

View File

@ -19,189 +19,126 @@
package org.apache.cassandra.db;
import java.io.IOException;
import java.util.Iterator;
import java.math.BigInteger;
import org.apache.cassandra.io.Coordinate;
import org.apache.cassandra.continuations.Suspendable;
import org.apache.cassandra.io.DataInputBuffer;
import org.apache.cassandra.io.DataOutputBuffer;
import org.apache.cassandra.io.IFileReader;
import org.apache.cassandra.io.SSTable;
import org.apache.cassandra.io.SequenceFile;
import org.apache.cassandra.service.PartitionerType;
import org.apache.cassandra.service.StorageService;
public class FileStruct implements Comparable<FileStruct>, Iterable<String>
public class FileStruct implements Comparable<FileStruct>
{
IFileReader reader_;
String key_;
DataInputBuffer bufIn_;
DataOutputBuffer bufOut_;
private String key = null;
private boolean exhausted = false;
private IFileReader reader;
private DataInputBuffer bufIn;
private DataOutputBuffer bufOut;
public FileStruct(IFileReader reader)
public FileStruct()
{
this.reader = reader;
bufIn = new DataInputBuffer();
bufOut = new DataOutputBuffer();
}
public String getFileName()
public FileStruct(String file, int bufSize) throws IOException
{
return reader.getFileName();
bufIn_ = new DataInputBuffer();
bufOut_ = new DataOutputBuffer();
reader_ = SequenceFile.bufferedReader(file, bufSize);
long bytesRead = advance();
if ( bytesRead == -1L )
throw new IOException("Either the file is empty or EOF has been reached.");
}
public void close() throws IOException
{
reader.close();
}
public boolean isExhausted()
{
return exhausted;
}
public DataInputBuffer getBufIn()
{
return bufIn;
}
public String getKey()
{
String key = key_;
if ( !key.equals(SSTable.blockIndexKey_) )
{
PartitionerType pType = StorageService.getPartitionerType();
switch ( pType )
{
case OPHF:
break;
default:
String[] peices = key.split(":");
key = peices[1];
break;
}
}
return key;
}
public DataOutputBuffer getBuffer()
{
return bufOut_;
}
public long advance() throws IOException
{
long bytesRead = -1L;
bufOut_.reset();
/* advance and read the next key in the file. */
if (reader_.isEOF())
{
reader_.close();
return bytesRead;
}
bytesRead = reader_.next(bufOut_);
if (bytesRead == -1)
{
reader_.close();
return bytesRead;
}
bufIn_.reset(bufOut_.getData(), bufOut_.getLength());
key_ = bufIn_.readUTF();
/* If the key we read is the Block Index Key then omit and read the next key. */
if ( key_.equals(SSTable.blockIndexKey_) )
{
bufOut_.reset();
bytesRead = reader_.next(bufOut_);
if (bytesRead == -1)
{
reader_.close();
return bytesRead;
}
bufIn_.reset(bufOut_.getData(), bufOut_.getLength());
key_ = bufIn_.readUTF();
}
return bytesRead;
}
public int compareTo(FileStruct f)
{
return key.compareTo(f.key);
int value = 0;
PartitionerType pType = StorageService.getPartitionerType();
switch( pType )
{
case OPHF:
value = key_.compareTo(f.key_);
break;
default:
String lhs = key_.split(":")[0];
BigInteger b = new BigInteger(lhs);
String rhs = f.key_.split(":")[0];
BigInteger b2 = new BigInteger(rhs);
value = b.compareTo(b2);
break;
}
return value;
}
// we don't use SequenceReader.seekTo, since that (sometimes) throws an exception
// if the key is not found. unsure if this behavior is desired.
public void seekTo(String seekKey)
public void close() throws IOException
{
try
{
Coordinate range = SSTable.getCoordinates(seekKey, reader);
reader.seek(range.end_);
long position = reader.getPositionFromBlockIndex(seekKey);
if (position == -1)
{
reader.seek(range.start_);
}
else
{
reader.seek(position);
}
while (!exhausted)
{
getNextKey();
if (key.compareTo(seekKey) >= 0)
{
break;
}
}
}
catch (IOException e)
{
throw new RuntimeException("corrupt sstable", e);
}
}
/*
* Read the next key from the data file, skipping block indexes.
* Caller must check isExhausted after each call to see if further
* reads are valid.
*/
public void getNextKey()
{
if (exhausted)
{
throw new IndexOutOfBoundsException();
}
try
{
bufOut.reset();
if (reader.isEOF())
{
reader.close();
exhausted = true;
return;
}
long bytesread = reader.next(bufOut);
if (bytesread == -1)
{
reader.close();
exhausted = true;
return;
}
bufIn.reset(bufOut.getData(), bufOut.getLength());
key = bufIn.readUTF();
/* If the key we read is the Block Index Key then omit and read the next key. */
if (key.equals(SSTable.blockIndexKey_))
{
bufOut.reset();
bytesread = reader.next(bufOut);
if (bytesread == -1)
{
reader.close();
exhausted = true;
return;
}
bufIn.reset(bufOut.getData(), bufOut.getLength());
key = bufIn.readUTF();
}
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
public Iterator<String> iterator()
{
return new FileStructIterator();
}
private class FileStructIterator implements Iterator<String>
{
String saved;
public FileStructIterator()
{
if (getKey() == null && !isExhausted())
{
forward();
}
}
private void forward()
{
getNextKey();
saved = isExhausted() ? null : getKey();
}
public boolean hasNext()
{
return saved != null;
}
public String next()
{
if (saved == null)
{
throw new IndexOutOfBoundsException();
}
String key = saved;
forward();
return key;
}
public void remove()
{
throw new UnsupportedOperationException();
}
bufIn_.close();
bufOut_.close();
reader_.close();
}
}

View File

@ -6,6 +6,13 @@ class FileStructComparator implements Comparator<FileStruct>
{
public int compare(FileStruct f, FileStruct f2)
{
return f.getFileName().compareTo(f2.getFileName());
return f.reader_.getFileName().compareTo(f2.reader_.getFileName());
}
public boolean equals(Object o)
{
if (!(o instanceof FileStructComparator))
return false;
return true;
}
}

View File

@ -24,8 +24,6 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.log4j.Logger;
import org.apache.cassandra.concurrent.DebuggableScheduledThreadPoolExecutor;
import org.apache.cassandra.concurrent.ThreadFactoryImpl;
import org.apache.cassandra.config.DatabaseDescriptor;
@ -34,7 +32,11 @@ import org.apache.cassandra.net.EndPoint;
import org.apache.cassandra.net.Message;
import org.apache.cassandra.net.MessagingService;
import org.apache.cassandra.service.IComponentShutdown;
import org.apache.cassandra.service.IResponseResolver;
import org.apache.cassandra.service.QuorumResponseHandler;
import org.apache.cassandra.service.StorageService;
import org.apache.cassandra.service.WriteResponseResolver;
import org.apache.log4j.Logger;
/**
@ -108,14 +110,14 @@ public class HintedHandOffManager implements IComponentShutdown
private void deleteEndPoint(String endpointAddress, String key) throws Exception
{
RowMutation rm = new RowMutation(DatabaseDescriptor.getTables().get(0), key_);
rm.delete(Table.hints_ + ":" + key + ":" + endpointAddress, System.currentTimeMillis());
rm.delete(Table.hints_ + ":" + key + ":" + endpointAddress);
rm.apply();
}
private void deleteKey(String key) throws Exception
{
RowMutation rm = new RowMutation(DatabaseDescriptor.getTables().get(0), key_);
rm.delete(Table.hints_ + ":" + key, System.currentTimeMillis());
rm.delete(Table.hints_ + ":" + key);
rm.apply();
}
@ -140,7 +142,7 @@ public class HintedHandOffManager implements IComponentShutdown
if(hintedColumnFamily == null)
{
// Force flush now
columnFamilyStore_.forceFlush();
columnFamilyStore_.forceFlush(false);
return;
}
Collection<IColumn> keys = hintedColumnFamily.getAllColumns();
@ -175,7 +177,7 @@ public class HintedHandOffManager implements IComponentShutdown
}
}
// Force flush now
columnFamilyStore_.forceFlush();
columnFamilyStore_.forceFlush(false);
// Now do a major compaction
columnFamilyStore_.forceCompaction(null, null, 0, null);

View File

@ -29,7 +29,6 @@ public interface IColumn
{
public static short UtfPrefix_ = 2;
public boolean isMarkedForDelete();
public long getMarkedForDeleteAt();
public String name();
public int size();
public int serializedSize();
@ -40,7 +39,10 @@ public interface IColumn
public Collection<IColumn> getSubColumns();
public IColumn getSubColumn(String columnName);
public void addColumn(String name, IColumn column);
public void delete();
public void repair(IColumn column);
public IColumn diff(IColumn column);
public boolean putColumn(IColumn column);
public int getObjectCount();
public byte[] digest();
public byte[] digest();
}

View File

@ -20,14 +20,7 @@ package org.apache.cassandra.db;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Iterator;
import java.util.PriorityQueue;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@ -38,16 +31,19 @@ import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.log4j.Logger;
import org.apache.cassandra.concurrent.DebuggableThreadPoolExecutor;
import org.apache.cassandra.concurrent.ThreadFactoryImpl;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.io.DataOutputBuffer;
import org.apache.cassandra.io.SSTable;
import org.apache.cassandra.service.IComponentShutdown;
import org.apache.cassandra.service.PartitionerType;
import org.apache.cassandra.service.StorageService;
import org.apache.cassandra.utils.BloomFilter;
import org.apache.cassandra.utils.LogUtil;
import org.apache.cassandra.utils.DestructivePQIterator;
import org.apache.log4j.Logger;
import org.apache.cassandra.io.*;
import org.apache.cassandra.utils.*;
/**
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
@ -82,6 +78,7 @@ public class Memtable implements MemtableMBean, Comparable<Memtable>
private Map<String, ColumnFamily> columnFamilies_ = new HashMap<String, ColumnFamily>();
/* Lock and Condition for notifying new clients about Memtable switches */
Lock lock_ = new ReentrantLock();
Condition condition_;
Memtable(String table, String cfName) throws IOException
{
@ -96,6 +93,7 @@ public class Memtable implements MemtableMBean, Comparable<Memtable>
));
}
condition_ = lock_.newCondition();
table_ = table;
cfName_ = cfName;
creationTime_ = System.currentTimeMillis();
@ -129,7 +127,7 @@ public class Memtable implements MemtableMBean, Comparable<Memtable>
key_ = key;
columnFamilyName_ = cfName;
}
Getter(String key, String cfName, IFilter filter)
{
this(key, cfName);
@ -138,11 +136,29 @@ public class Memtable implements MemtableMBean, Comparable<Memtable>
public ColumnFamily call()
{
ColumnFamily cf = getLocalCopy(key_, columnFamilyName_, filter_);
ColumnFamily cf = getLocalCopy(key_, columnFamilyName_, filter_);
return cf;
}
}
class Remover implements Runnable
{
private String key_;
private ColumnFamily columnFamily_;
Remover(String key, ColumnFamily columnFamily)
{
key_ = key;
columnFamily_ = columnFamily;
}
public void run()
{
columnFamily_.delete();
columnFamilies_.put(key_, columnFamily_);
}
}
/**
* Flushes the current memtable to disk.
*
@ -166,7 +182,7 @@ public class Memtable implements MemtableMBean, Comparable<Memtable>
}
/**
* Compares two Memtable based on creation time.
* Compares two Memtable based on creation time.
* @param rhs
* @return
*/
@ -196,6 +212,13 @@ public class Memtable implements MemtableMBean, Comparable<Memtable>
currentObjectCount_.addAndGet(newCount - oldCount);
}
private boolean isLifetimeViolated()
{
/* Memtable lifetime in terms of milliseconds */
long lifetimeInMillis = DatabaseDescriptor.getMemtableLifetime() * 3600 * 1000;
return ( ( System.currentTimeMillis() - creationTime_ ) >= lifetimeInMillis );
}
boolean isThresholdViolated(String key)
{
boolean bVal = false;//isLifetimeViolated();
@ -263,30 +286,27 @@ public class Memtable implements MemtableMBean, Comparable<Memtable>
/*
* This version is used to switch memtable and force flush.
*/
public void forceflush(ColumnFamilyStore cfStore) throws IOException
void forceflush(ColumnFamilyStore cfStore, boolean fRecovery) throws IOException
{
RowMutation rm = new RowMutation(DatabaseDescriptor.getTables().get(0), flushKey_);
try
if(!fRecovery)
{
if (cfStore.isSuper())
{
rm.add(cfStore.getColumnFamilyName() + ":SC1:Column", "0".getBytes(), 0);
} else {
rm.add(cfStore.getColumnFamilyName() + ":Column", "0".getBytes(), 0);
}
rm.apply();
RowMutation rm = new RowMutation(DatabaseDescriptor.getTables().get(0), flushKey_);
try
{
rm.add(cfStore.columnFamily_ + ":Column","0".getBytes());
rm.apply();
}
catch(ColumnFamilyNotDefinedException ex)
{
logger_.debug(LogUtil.throwableToString(ex));
}
}
catch(ColumnFamilyNotDefinedException ex)
else
{
logger_.debug(LogUtil.throwableToString(ex));
flush(CommitLog.CommitLogContext.NULL);
}
}
void flushOnRecovery() throws IOException {
flush(CommitLog.CommitLogContext.NULL);
}
private void resolve(String key, ColumnFamily columnFamily)
{
ColumnFamily oldCf = columnFamilies_.get(key);
@ -299,7 +319,6 @@ public class Memtable implements MemtableMBean, Comparable<Memtable>
int newObjectCount = oldCf.getColumnCount();
resolveSize(oldSize, newSize);
resolveCount(oldObjectCount, newObjectCount);
oldCf.delete(Math.max(oldCf.getMarkedForDeleteAt(), columnFamily.getMarkedForDeleteAt()));
}
else
{
@ -320,46 +339,68 @@ public class Memtable implements MemtableMBean, Comparable<Memtable>
resolve(key, columnFamily);
}
ColumnFamily getLocalCopy(String key, String columnFamilyColumn, IFilter filter)
ColumnFamily getLocalCopy(String key, String cfName, IFilter filter)
{
String[] values = RowMutation.getColumnAndColumnFamily(columnFamilyColumn);
String[] values = RowMutation.getColumnAndColumnFamily(cfName);
ColumnFamily columnFamily = null;
if(values.length == 1 )
{
columnFamily = columnFamilies_.get(key);
columnFamily = columnFamilies_.get(key);
}
else
{
ColumnFamily cFamily = columnFamilies_.get(key);
if (cFamily == null) return null;
if (values.length == 2) {
IColumn column = cFamily.getColumn(values[1]); // super or normal column
if (column != null )
{
columnFamily = new ColumnFamily(cfName_);
columnFamily.addColumn(column);
}
if(cFamily == null)
return null;
IColumn column = null;
if(values.length == 2)
{
column = cFamily.getColumn(values[1]);
if(column != null )
{
columnFamily = new ColumnFamily(cfName_);
columnFamily.addColumn(column.name(), column);
}
}
else
{
assert values.length == 3;
SuperColumn superColumn = (SuperColumn)cFamily.getColumn(values[1]);
if (superColumn != null)
{
IColumn subColumn = superColumn.getSubColumn(values[2]);
if (subColumn != null)
{
columnFamily = new ColumnFamily(cfName_);
columnFamily.addColumn(values[1] + ":" + values[2], subColumn.value(), subColumn.timestamp(), subColumn.isMarkedForDelete());
}
}
else
{
column = cFamily.getColumn(values[1]);
if(column != null )
{
IColumn subColumn = ((SuperColumn)column).getSubColumn(values[2]);
if(subColumn != null)
{
columnFamily = new ColumnFamily(cfName_);
columnFamily.createColumn(values[1] + ":" + values[2], subColumn.value(), subColumn.timestamp());
}
}
}
}
/* Filter unnecessary data from the column based on the provided filter */
return filter.filter(columnFamilyColumn, columnFamily);
return filter.filter(cfName, columnFamily);
}
ColumnFamily get(String key, String cfName)
{
printExecutorStats();
Callable<ColumnFamily> call = new Getter(key, cfName);
ColumnFamily cf = null;
try
{
cf = apartments_.get(cfName_).submit(call).get();
}
catch ( ExecutionException ex )
{
logger_.debug(LogUtil.throwableToString(ex));
}
catch ( InterruptedException ex2 )
{
logger_.debug(LogUtil.throwableToString(ex2));
}
return cf;
}
ColumnFamily get(String key, String cfName, IFilter filter)
{
printExecutorStats();
@ -380,6 +421,23 @@ public class Memtable implements MemtableMBean, Comparable<Memtable>
return cf;
}
/*
* Although the method is named remove() we cannot remove the key
* from memtable. We add it to the memtable but mark it as deleted.
* The reason for this because we do not want a successive get()
* for the same key to scan the ColumnFamilyStore files for this key.
*/
void remove(String key, ColumnFamily columnFamily) throws IOException
{
printExecutorStats();
Runnable deleter = new Remover(key, columnFamily);
apartments_.get(cfName_).submit(deleter);
}
/*
* param recoveryMode - indicates if this was invoked during
* recovery.
*/
void flush(CommitLog.CommitLogContext cLogCtx) throws IOException
{
ColumnFamilyStore cfStore = Table.open(table_).getColumnFamilyStore(cfName_);
@ -392,9 +450,51 @@ public class Memtable implements MemtableMBean, Comparable<Memtable>
return;
}
PartitionerType pType = StorageService.getPartitionerType();
String directory = DatabaseDescriptor.getDataFileLocation();
String filename = cfStore.getNextFileName();
SSTable ssTable = new SSTable(directory, filename);
SSTable ssTable = new SSTable(directory, filename, pType);
switch (pType)
{
case OPHF:
flushForOrderPreservingPartitioner(ssTable, cfStore, cLogCtx);
break;
default:
flushForRandomPartitioner(ssTable, cfStore, cLogCtx);
break;
}
}
private void flushForRandomPartitioner(SSTable ssTable, ColumnFamilyStore cfStore, CommitLog.CommitLogContext cLogCtx) throws IOException
{
/* List of primary keys in sorted order */
List<PrimaryKey> pKeys = PrimaryKey.create( columnFamilies_.keySet() );
DataOutputBuffer buffer = new DataOutputBuffer();
/* Use this BloomFilter to decide if a key exists in a SSTable */
BloomFilter bf = new BloomFilter(pKeys.size(), 15);
for ( PrimaryKey pKey : pKeys )
{
buffer.reset();
ColumnFamily columnFamily = columnFamilies_.get(pKey.key());
if ( columnFamily != null )
{
/* serialize the cf with column indexes */
ColumnFamily.serializer2().serialize( columnFamily, buffer );
/* Now write the key and value to disk */
ssTable.append(pKey.key(), pKey.hash(), buffer);
bf.fill(pKey.key());
columnFamily.clear();
}
}
ssTable.close(bf);
cfStore.onMemtableFlush(cLogCtx);
cfStore.storeLocation( ssTable.getDataFileLocation(), bf );
buffer.close();
}
private void flushForOrderPreservingPartitioner(SSTable ssTable, ColumnFamilyStore cfStore, CommitLog.CommitLogContext cLogCtx) throws IOException
{
List<String> keys = new ArrayList<String>( columnFamilies_.keySet() );
Collections.sort(keys);
DataOutputBuffer buffer = new DataOutputBuffer();
@ -407,7 +507,7 @@ public class Memtable implements MemtableMBean, Comparable<Memtable>
if ( columnFamily != null )
{
/* serialize the cf with column indexes */
ColumnFamily.serializerWithIndexes().serialize( columnFamily, buffer );
ColumnFamily.serializer2().serialize( columnFamily, buffer );
/* Now write the key and value to disk */
ssTable.append(key, buffer);
bf.fill(key);
@ -418,13 +518,5 @@ public class Memtable implements MemtableMBean, Comparable<Memtable>
cfStore.onMemtableFlush(cLogCtx);
cfStore.storeLocation( ssTable.getDataFileLocation(), bf );
buffer.close();
columnFamilies_.clear();
}
public Iterator<String> sortedKeyIterator()
{
return new DestructivePQIterator<String>(new PriorityQueue<String>(columnFamilies_.keySet()));
}
}

View File

@ -27,8 +27,10 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.cassandra.concurrent.DebuggableThreadPoolExecutor;
import org.apache.cassandra.concurrent.ThreadFactoryImpl;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.utils.LogUtil;
import org.apache.log4j.Logger;
import org.apache.cassandra.utils.*;
/**
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
@ -40,7 +42,7 @@ public class MemtableManager
private static Lock lock_ = new ReentrantLock();
private static Logger logger_ = Logger.getLogger(MemtableManager.class);
private ReentrantReadWriteLock rwLock_ = new ReentrantReadWriteLock(true);
public static MemtableManager instance()
static MemtableManager instance()
{
if ( instance_ == null )
{
@ -157,22 +159,7 @@ public class MemtableManager
}
}
public List<Memtable> getUnflushedMemtables(String cfName)
{
rwLock_.readLock().lock();
try
{
List<Memtable> memtables = history_.get(cfName);
if (memtables != null)
{
return new ArrayList<Memtable>(memtables);
}
return Arrays.asList(new Memtable[0]);
}
finally
{
rwLock_.readLock().unlock();
}
}
}

View File

@ -87,6 +87,10 @@ class MinorCompactionManager implements IComponentShutdown
columnFamilyStore_.doCompaction();
logger_.debug("Finished compaction ..."+columnFamilyStore_.columnFamily_);
}
catch (IOException e)
{
logger_.debug( LogUtil.throwableToString(e) );
}
catch (Throwable th)
{
logger_.error( LogUtil.throwableToString(th) );
@ -118,9 +122,16 @@ class MinorCompactionManager implements IComponentShutdown
public Boolean call()
{
boolean result = true;
logger_.debug("Started compaction ..."+columnFamilyStore_.columnFamily_);
result = columnFamilyStore_.doAntiCompaction(ranges_, target_,fileList_);
logger_.debug("Finished compaction ..."+columnFamilyStore_.columnFamily_);
try
{
logger_.debug("Started compaction ..."+columnFamilyStore_.columnFamily_);
result = columnFamilyStore_.doAntiCompaction(ranges_, target_,fileList_);
logger_.debug("Finished compaction ..."+columnFamilyStore_.columnFamily_);
}
catch (IOException e)
{
logger_.debug( LogUtil.throwableToString(e) );
}
return result;
}
}
@ -169,6 +180,10 @@ class MinorCompactionManager implements IComponentShutdown
columnFamilyStore_.doCleanupCompaction();
logger_.debug("Finished compaction ..."+columnFamilyStore_.columnFamily_);
}
catch (IOException e)
{
logger_.debug( LogUtil.throwableToString(e) );
}
catch (Throwable th)
{
logger_.error( LogUtil.throwableToString(th) );
@ -208,9 +223,14 @@ class MinorCompactionManager implements IComponentShutdown
public Future<Boolean> submit(ColumnFamilyStore columnFamilyStore, List<Range> ranges, EndPoint target, List<String> fileList)
{
return compactor_.submit( new FileCompactor2(columnFamilyStore, ranges, target, fileList) );
}
public Future<Boolean> submit(ColumnFamilyStore columnFamilyStore, List<Range> ranges)
{
return compactor_.submit( new FileCompactor2(columnFamilyStore, ranges) );
}
public void submitMajor(ColumnFamilyStore columnFamilyStore, long skip)
public void submitMajor(ColumnFamilyStore columnFamilyStore, List<Range> ranges, long skip)
{
compactor_.submit( new OnDemandCompactor(columnFamilyStore, skip) );
}

View File

@ -32,13 +32,13 @@ import org.apache.cassandra.io.SSTable;
public class NamesFilter implements IFilter
{
/* list of column names to filter against. */
private List<String> names_;
private List<String> names_ = new ArrayList<String>();
NamesFilter(List<String> names)
{
names_ = new ArrayList<String>(names);
names_ = names;
}
public ColumnFamily filter(String cf, ColumnFamily columnFamily)
{
if ( columnFamily == null )
@ -55,8 +55,8 @@ public class NamesFilter implements IFilter
{
if ( names_.contains(column.name()) )
{
names_.remove(column.name());
filteredCf.addColumn(column);
names_.remove(column.name());
filteredCf.addColumn(column.name(), column);
}
if( isDone() )
{
@ -64,20 +64,20 @@ public class NamesFilter implements IFilter
}
}
}
else if ( values.length == 2 && DatabaseDescriptor.getColumnType(cfName).equals("Super"))
else if ( values.length == 2 && DatabaseDescriptor.getColumnType(cfName).equals("Super") )
{
Collection<IColumn> columns = columnFamily.getAllColumns();
for(IColumn column : columns)
{
SuperColumn superColumn = (SuperColumn)column;
SuperColumn filteredSuperColumn = new SuperColumn(superColumn.name());
filteredCf.addColumn(filteredSuperColumn);
filteredCf.addColumn(filteredSuperColumn.name(), filteredSuperColumn);
Collection<IColumn> subColumns = superColumn.getSubColumns();
for(IColumn subColumn : subColumns)
{
if ( names_.contains(subColumn.name()) )
{
names_.remove(subColumn.name());
names_.remove(subColumn.name());
filteredSuperColumn.addColumn(subColumn.name(), subColumn);
}
if( isDone() )
@ -87,28 +87,28 @@ public class NamesFilter implements IFilter
}
}
}
else
else
{
throw new UnsupportedOperationException();
}
return filteredCf;
}
public IColumn filter(IColumn column, DataInputStream dis) throws IOException
{
{
String columnName = column.name();
if ( names_.contains(columnName) )
{
names_.remove(columnName);
names_.remove(columnName);
}
else
{
column = null;
}
return column;
}
public boolean isDone()
{
return names_.isEmpty();

View File

@ -0,0 +1,124 @@
/**
* 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.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.apache.cassandra.io.ICompactSerializer;
import org.apache.cassandra.service.PartitionerType;
import org.apache.cassandra.service.StorageService;
import org.apache.cassandra.utils.FBUtilities;
public class PrimaryKey implements Comparable<PrimaryKey>
{
public static List<PrimaryKey> create(Set<String> keys)
{
List<PrimaryKey> list = new ArrayList<PrimaryKey>();
for ( String key : keys )
{
list.add( new PrimaryKey(key) );
}
Collections.sort(list);
return list;
}
/* MD5 hash of the key_ */
private BigInteger hash_;
/* Key used by the application */
private String key_;
PrimaryKey(String key)
{
PartitionerType pType = StorageService.getPartitionerType();
switch (pType)
{
case RANDOM:
hash_ = FBUtilities.hash(key);
break;
case OPHF:
break;
default:
hash_ = hash_ = FBUtilities.hash(key);
break;
}
key_ = key;
}
PrimaryKey(String key, BigInteger hash)
{
hash_ = hash;
key_ = key;
}
public String key()
{
return key_;
}
public BigInteger hash()
{
return hash_;
}
/**
* This performs semantic comparison of Primary Keys.
* If the partition algorithm chosen is "Random" then
* the hash of the key is used for comparison. If it
* is an OPHF then the key is used.
*
* @param rhs primary against which we wish to compare.
* @return
*/
public int compareTo(PrimaryKey rhs)
{
int value = 0;
PartitionerType pType = StorageService.getPartitionerType();
switch (pType)
{
case RANDOM:
value = hash_.compareTo(rhs.hash_);
break;
case OPHF:
value = key_.compareTo(rhs.key_);
break;
default:
value = hash_.compareTo(rhs.hash_);
break;
}
return value;
}
@Override
public String toString()
{
return (hash_ != null) ? (key_ + ":" + hash_) : key_;
}
}

View File

@ -93,6 +93,7 @@ public class RecoveryManager
public static void main(String[] args) throws Throwable
{
DatabaseDescriptor.init();
long start = System.currentTimeMillis();
RecoveryManager rm = RecoveryManager.instance();
rm.doRecovery();

View File

@ -18,109 +18,132 @@
package org.apache.cassandra.db;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import java.io.Serializable;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.cassandra.io.ICompactSerializer;
import org.apache.cassandra.utils.FBUtilities;
import org.apache.log4j.Logger;
import org.apache.cassandra.io.*;
public class Row
/**
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
*/
public class Row implements Serializable
{
private static RowSerializer serializer_ = new RowSerializer();
private static Logger logger_ = Logger.getLogger(Row.class);
private static ICompactSerializer<Row> serializer_;
private static Logger logger_ = Logger.getLogger(Row.class);
static RowSerializer serializer()
static
{
serializer_ = new RowSerializer();
}
static ICompactSerializer<Row> serializer()
{
return serializer_;
}
private String key_;
private String key_;
private Map<String, ColumnFamily> columnFamilies_ = new Hashtable<String, ColumnFamily>();
private transient AtomicInteger size_ = new AtomicInteger(0);
/* Ctor for JAXB */
protected Row()
{
}
public Row(String key)
{
key_ = key;
key_ = key;
}
public String key()
{
return key_;
}
void key(String key)
{
key_ = key;
}
public Set<String> getColumnFamilyNames()
{
return columnFamilies_.keySet();
}
public Collection<ColumnFamily> getColumnFamilies()
{
return columnFamilies_.values();
}
@Deprecated
// (use getColumnFamilies or getColumnFamilyNames)
public Map<String, ColumnFamily> getColumnFamilyMap()
{
return columnFamilies_;
}
public ColumnFamily getColumnFamily(String cfName)
{
return columnFamilies_.get(cfName);
}
public Map<String, ColumnFamily> getColumnFamilies()
{
return columnFamilies_;
}
void addColumnFamily(ColumnFamily columnFamily)
{
columnFamilies_.put(columnFamily.name(), columnFamily);
size_.addAndGet(columnFamily.size());
}
void removeColumnFamily(ColumnFamily columnFamily)
{
columnFamilies_.remove(columnFamily.name());
int delta = (-1) * columnFamily.size();
size_.addAndGet(delta);
}
public int size()
{
return size_.get();
}
public boolean isEmpty()
{
return (columnFamilies_.size() == 0);
return ( columnFamilies_.size() == 0 );
}
/**
* This is used as oldRow.merge(newRow). Basically we take the newRow
* and merge it into the oldRow.
*/
void merge(Row row)
{
Map<String, ColumnFamily> columnFamilies = row.getColumnFamilies();
Set<String> cfNames = columnFamilies.keySet();
for ( String cfName : cfNames )
{
ColumnFamily cf = columnFamilies_.get(cfName);
if ( cf == null )
columnFamilies_.put(cfName, columnFamilies.get(cfName));
else
{
cf.merge(columnFamilies.get(cfName));
}
}
}
/*
/**
* This function will repair the current row with the input row
* what that means is that if there are any differences between the 2 rows then
* this fn will make the current row take the latest changes .
*/
public void repair(Row row)
{
Map<String, ColumnFamily> columnFamilies = row.getColumnFamilyMap();
Map<String, ColumnFamily> columnFamilies = row.getColumnFamilies();
Set<String> cfNames = columnFamilies.keySet();
for (String cfName : cfNames)
for ( String cfName : cfNames )
{
ColumnFamily cf = columnFamilies_.get(cfName);
if (cf == null)
if ( cf == null )
{
cf = new ColumnFamily(cfName);
cf = new ColumnFamily(cfName);
columnFamilies_.put(cfName, cf);
}
cf.repair(columnFamilies.get(cfName));
@ -128,7 +151,7 @@ public class Row
}
/*
/**
* This function will calculate the difference between 2 rows
* and return the resultant row. This assumes that the row that
* is being submitted is a super set of the current row so
@ -139,82 +162,78 @@ public class Row
public Row diff(Row row)
{
Row rowDiff = new Row(key_);
Map<String, ColumnFamily> columnFamilies = row.getColumnFamilyMap();
Map<String, ColumnFamily> columnFamilies = row.getColumnFamilies();
Set<String> cfNames = columnFamilies.keySet();
for (String cfName : cfNames)
for ( String cfName : cfNames )
{
ColumnFamily cf = columnFamilies_.get(cfName);
ColumnFamily cfDiff = null;
if (cf == null)
rowDiff.getColumnFamilyMap().put(cfName, columnFamilies.get(cfName));
if ( cf == null )
rowDiff.getColumnFamilies().put(cfName, columnFamilies.get(cfName));
else
{
cfDiff = cf.diff(columnFamilies.get(cfName));
if (cfDiff != null)
rowDiff.getColumnFamilyMap().put(cfName, cfDiff);
cfDiff = cf.diff(columnFamilies.get(cfName));
if(cfDiff != null)
rowDiff.getColumnFamilies().put(cfName, cfDiff);
}
}
if (rowDiff.getColumnFamilyMap().size() != 0)
return rowDiff;
if(rowDiff.getColumnFamilies().size() != 0)
return rowDiff;
else
return null;
return null;
}
public Row cloneMe()
{
Row row = new Row(key_);
row.columnFamilies_ = new HashMap<String, ColumnFamily>(columnFamilies_);
return row;
Row row = new Row(key_);
row.columnFamilies_ = new HashMap<String, ColumnFamily>(columnFamilies_);
return row;
}
public byte[] digest()
{
long start = System.currentTimeMillis();
Set<String> cfamilies = columnFamilies_.keySet();
byte[] xorHash = ArrayUtils.EMPTY_BYTE_ARRAY;
for (String cFamily : cfamilies)
{
if (xorHash.length == 0)
{
xorHash = columnFamilies_.get(cFamily).digest();
}
else
{
byte[] tmpHash = columnFamilies_.get(cFamily).digest();
xorHash = FBUtilities.xor(xorHash, tmpHash);
}
}
Set<String> cfamilies = columnFamilies_.keySet();
byte[] xorHash = new byte[0];
byte[] tmpHash = new byte[0];
for(String cFamily : cfamilies)
{
if(xorHash.length == 0)
{
xorHash = columnFamilies_.get(cFamily).digest();
}
else
{
tmpHash = columnFamilies_.get(cFamily).digest();
xorHash = FBUtilities.xor(xorHash, tmpHash);
}
}
logger_.info("DIGEST TIME: " + (System.currentTimeMillis() - start)
+ " ms.");
return xorHash;
+ " ms.");
return xorHash;
}
void clear()
{
{
columnFamilies_.clear();
}
public String toString()
{
return "Row(" + key_ + " [" + StringUtils.join(columnFamilies_.values(), ", ") + ")]";
}
}
class RowSerializer implements ICompactSerializer<Row>
{
public void serialize(Row row, DataOutputStream dos) throws IOException
{
dos.writeUTF(row.key());
Map<String, ColumnFamily> columnFamilies = row.getColumnFamilyMap();
int size = columnFamilies.size();
dos.writeUTF(row.key());
Map<String, ColumnFamily> columnFamilies = row.getColumnFamilies();
int size = columnFamilies.size();
dos.writeInt(size);
if (size > 0)
{
Set<String> cNames = columnFamilies.keySet();
for (String cName : cNames)
{
if ( size > 0 )
{
Set<String> cNames = columnFamilies.keySet();
for ( String cName : cNames )
{
ColumnFamily.serializer().serialize(columnFamilies.get(cName), dos);
}
}
@ -222,13 +241,13 @@ class RowSerializer implements ICompactSerializer<Row>
public Row deserialize(DataInputStream dis) throws IOException
{
String key = dis.readUTF();
Row row = new Row(key);
String key = dis.readUTF();
Row row = new Row(key);
int size = dis.readInt();
if (size > 0)
{
for (int i = 0; i < size; ++i)
if ( size > 0 )
{
for ( int i = 0; i < size; ++i )
{
ColumnFamily cf = ColumnFamily.serializer().deserialize(dis);
row.addColumnFamily(cf);

View File

@ -18,30 +18,13 @@
package org.apache.cassandra.db;
import java.io.ByteArrayOutputStream;
import java.util.*;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.cassandra.io.ICompactSerializer;
import org.apache.cassandra.net.EndPoint;
import org.apache.cassandra.net.Message;
import org.apache.cassandra.service.StorageService;
import org.apache.cassandra.service.batch_mutation_super_t;
import org.apache.cassandra.service.batch_mutation_t;
import org.apache.cassandra.service.column_t;
import org.apache.cassandra.service.superColumn_t;
import org.apache.cassandra.utils.FBUtilities;
/**
@ -49,107 +32,121 @@ import org.apache.cassandra.utils.FBUtilities;
*/
public class RowMutation implements Serializable
{
private static ICompactSerializer<RowMutation> serializer_;
public static final String HINT = "HINT";
{
private static ICompactSerializer<RowMutation> serializer_;
static
{
serializer_ = new RowMutationSerializer();
}
}
static ICompactSerializer<RowMutation> serializer()
{
return serializer_;
}
private String table_;
private String key_;
protected Map<String, ColumnFamily> modifications_ = new HashMap<String, ColumnFamily>();
private String key_;
protected Map<String, ColumnFamily> modifications_ = new HashMap<String, ColumnFamily>();
protected Map<String, ColumnFamily> deletions_ = new HashMap<String, ColumnFamily>();
/* Ctor for JAXB */
private RowMutation()
{
}
public RowMutation(String table, String key)
{
table_ = table;
key_ = key;
}
public RowMutation(String table, Row row)
{
table_ = table;
key_ = row.key();
for (ColumnFamily cf : row.getColumnFamilies())
Map<String, ColumnFamily> cfSet = row.getColumnFamilies();
Set<String> keyset = cfSet.keySet();
for(String cfName : keyset)
{
add(cf);
add(cfName, cfSet.get(cfName));
}
}
protected RowMutation(String table, String key, Map<String, ColumnFamily> modifications)
protected RowMutation(String table, String key, Map<String, ColumnFamily> modifications, Map<String, ColumnFamily> deletions)
{
table_ = table;
key_ = key;
modifications_ = modifications;
table_ = table;
key_ = key;
modifications_ = modifications;
deletions_ = deletions;
}
public static String[] getColumnAndColumnFamily(String cf)
{
return cf.split(":");
}
String table()
{
return table_;
}
public String key()
{
return key_;
}
void addHints(String hint) throws IOException, ColumnFamilyNotDefinedException
{
{
String cfName = Table.hints_ + ":" + hint;
add(cfName, ArrayUtils.EMPTY_BYTE_ARRAY, 0);
add(cfName, new byte[0]);
}
/*
* Specify a column family name and the corresponding column
* family object.
* family object.
* param @ cf - column family name
* param @ columnFamily - the column family.
*/
public void add(ColumnFamily columnFamily)
{
if (modifications_.containsKey(columnFamily.name()))
{
throw new IllegalArgumentException("ColumnFamily " + columnFamily.name() + " is already being modified");
}
modifications_.put(columnFamily.name(), columnFamily);
public void add(String cf, ColumnFamily columnFamily)
{
modifications_.put(cf, columnFamily);
}
/*
* Specify a column name and a corresponding value for
* the column. Column name is specified as <column family>:column.
* This will result in a ColumnFamily associated with
* <column family> as name and a Column with <column>
* as name. The columan can be further broken up
* as name.
*
* param @ cf - column name as <column family>:<column>
* param @ value - value associated with the column
*/
public void add(String cf, byte[] value) throws IOException, ColumnFamilyNotDefinedException
{
add(cf, value, 0);
}
/*
* Specify a column name and a corresponding value for
* the column. Column name is specified as <column family>:column.
* This will result in a ColumnFamily associated with
* <column family> as name and a Column with <column>
* as name. The columan can be further broken up
* as super column name : columnname in case of super columns
*
*
* param @ cf - column name as <column family>:<column>
* param @ value - value associated with the column
* param @ timestamp - ts associated with this data.
*/
public void add(String cf, byte[] value, long timestamp)
{
{
String[] values = RowMutation.getColumnAndColumnFamily(cf);
if ( values.length == 0 || values.length == 1 || values.length > 3 )
throw new IllegalArgumentException("Column Family " + cf + " in invalid format. Must be in <column family>:<column> format.");
ColumnFamily columnFamily = modifications_.get(values[0]);
if( values.length == 2 )
{
@ -157,7 +154,7 @@ public class RowMutation implements Serializable
{
columnFamily = new ColumnFamily(values[0], ColumnFamily.getColumnType("Standard"));
}
columnFamily.addColumn(values[1], value, timestamp);
columnFamily.createColumn(values[1], value, timestamp);
}
if( values.length == 3 )
{
@ -165,203 +162,172 @@ public class RowMutation implements Serializable
{
columnFamily = new ColumnFamily(values[0], ColumnFamily.getColumnType("Super"));
}
columnFamily.addColumn(values[1]+ ":" + values[2], value, timestamp);
columnFamily.createColumn(values[1]+ ":" + values[2], value, timestamp);
}
modifications_.put(values[0], columnFamily);
}
public void delete(String columnFamilyColumn, long timestamp)
{
String[] values = RowMutation.getColumnAndColumnFamily(columnFamilyColumn);
String cfName = values[0];
if (modifications_.containsKey(cfName))
{
throw new IllegalArgumentException("ColumnFamily " + cfName + " is already being modified");
}
if (values.length == 0 || values.length > 3)
throw new IllegalArgumentException("Column Family " + columnFamilyColumn + " in invalid format. Must be in <column family>:<column> format.");
ColumnFamily columnFamily = modifications_.get(cfName);
if (columnFamily == null)
columnFamily = new ColumnFamily(cfName);
if (values.length == 2)
{
columnFamily.addColumn(values[1], ArrayUtils.EMPTY_BYTE_ARRAY, timestamp, true);
}
else if (values.length == 3)
{
columnFamily.addColumn(values[1] + ":" + values[2], ArrayUtils.EMPTY_BYTE_ARRAY, timestamp, true);
}
else
{
assert values.length == 1;
columnFamily.delete(timestamp);
}
modifications_.put(cfName, columnFamily);
}
/*
* Specify a column name to be deleted. Column name is
* specified as <column family>:column. This will result
* in a ColumnFamily associated with <column family> as
* name and perhaps Column with <column> as name being
* marked as deleted.
* TODO : Delete is NOT correct as we do not know
* the CF type so we need to fix that.
* param @ cf - column name as <column family>:<column>
*/
public void delete(String cf)
{
String[] values = RowMutation.getColumnAndColumnFamily(cf);
if ( values.length == 0 || values.length > 3 )
throw new IllegalArgumentException("Column Family " + cf + " in invalid format. Must be in <column family>:<column> format.");
ColumnFamily columnFamily = modifications_.get(values[0]);
if ( columnFamily == null )
columnFamily = new ColumnFamily(values[0]);
if(values.length == 2 )
{
columnFamily.createColumn( values[1]);
}
if(values.length == 3 )
{
columnFamily.createColumn( values[1] + ":" + values[2]);
}
deletions_.put(values[0], columnFamily);
}
/*
* This is equivalent to calling commit. Applies the changes to
* to the table that is obtained by calling Table.open().
*/
public void apply() throws IOException, ColumnFamilyNotDefinedException
{
{
Row row = new Row(key_);
apply(row);
}
/*
* Allows RowMutationVerbHandler to optimize by re-using a single Row object.
*/
void apply(Row emptyRow) throws IOException, ColumnFamilyNotDefinedException
{
assert emptyRow.getColumnFamilyMap().size() == 0;
Table table = Table.open(table_);
for (String cfName : modifications_.keySet())
{
if (!table.isValidColumnFamily(cfName))
Set<String> cfNames = modifications_.keySet();
for (String cfName : cfNames )
{
if ( !table.isValidColumnFamily(cfName) )
throw new ColumnFamilyNotDefinedException("Column Family " + cfName + " has not been defined.");
emptyRow.addColumnFamily(modifications_.get(cfName));
row.addColumnFamily( modifications_.get(cfName) );
}
table.apply(emptyRow);
table.apply(row);
Set<String> cfNames2 = deletions_.keySet();
for (String cfName : cfNames2 )
{
if ( !table.isValidColumnFamily(cfName) )
throw new ColumnFamilyNotDefinedException("Column Family " + cfName + " has not been defined.");
row.addColumnFamily( deletions_.get(cfName) );
}
if ( deletions_.size() > 0 )
table.delete(row);
}
/*
/*
* This is equivalent to calling commit. Applies the changes to
* to the table that is obtained by calling Table.open().
*/
void load(Row row) throws IOException, ColumnFamilyNotDefinedException, ExecutionException, InterruptedException
{
Table table = Table.open(table_);
void apply(Row row) throws IOException, ColumnFamilyNotDefinedException
{
Table table = Table.open(table_);
Set<String> cfNames = modifications_.keySet();
for (String cfName : cfNames)
{
if (!table.isValidColumnFamily(cfName))
for (String cfName : cfNames )
{
if ( !table.isValidColumnFamily(cfName) )
throw new ColumnFamilyNotDefinedException("Column Family " + cfName + " has not been defined.");
row.addColumnFamily(modifications_.get(cfName));
row.addColumnFamily( modifications_.get(cfName) );
}
table.apply(row);
Set<String> cfNames2 = deletions_.keySet();
for (String cfName : cfNames2 )
{
if ( !table.isValidColumnFamily(cfName) )
throw new ColumnFamilyNotDefinedException("Column Family " + cfName + " has not been defined.");
row.addColumnFamily( deletions_.get(cfName) );
}
if ( deletions_.size() > 0 )
table.delete(row);
}
/*
* This is equivalent to calling commit. Applies the changes to
* to the table that is obtained by calling Table.open().
*/
void load(Row row) throws IOException, ColumnFamilyNotDefinedException
{
Table table = Table.open(table_);
Set<String> cfNames = modifications_.keySet();
for (String cfName : cfNames )
{
if ( !table.isValidColumnFamily(cfName) )
throw new ColumnFamilyNotDefinedException("Column Family " + cfName + " has not been defined.");
row.addColumnFamily( modifications_.get(cfName) );
}
table.load(row);
}
public Message makeRowMutationMessage() throws IOException
{
return makeRowMutationMessage(StorageService.mutationVerbHandler_);
}
public Message makeRowMutationMessage(String verbHandlerName) throws IOException
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
serializer().serialize(this, dos);
EndPoint local = StorageService.getLocalStorageEndPoint();
EndPoint from = (local != null) ? local : new EndPoint(FBUtilities.getHostName(), 7000);
return new Message(from, StorageService.mutationStage_, verbHandlerName, bos.toByteArray());
}
public static RowMutation getRowMutation(batch_mutation_t batchMutation)
{
RowMutation rm = new RowMutation(batchMutation.table,
batchMutation.key.trim());
for (String cfname : batchMutation.cfmap.keySet())
{
List<column_t> list = batchMutation.cfmap.get(cfname);
for (column_t columnData : list)
{
rm.add(cfname + ":" + columnData.columnName,
columnData.value.getBytes(), columnData.timestamp);
}
}
return rm;
}
public static RowMutation getRowMutation(batch_mutation_super_t batchMutationSuper)
{
RowMutation rm = new RowMutation(batchMutationSuper.table,
batchMutationSuper.key.trim());
Set keys = batchMutationSuper.cfmap.keySet();
Iterator keyIter = keys.iterator();
while (keyIter.hasNext())
{
Object key = keyIter.next(); // Get the next key.
List<superColumn_t> list = batchMutationSuper.cfmap.get(key);
for (superColumn_t superColumnData : list)
{
if (superColumnData.columns.size() != 0)
{
for (column_t columnData : superColumnData.columns)
{
rm.add(key.toString() + ":" + superColumnData.name + ":" + columnData.columnName,
columnData.value.getBytes(), columnData.timestamp);
}
}
else
{
rm.add(key.toString() + ":" + superColumnData.name, ArrayUtils.EMPTY_BYTE_ARRAY, 0);
}
}
}
return rm;
}
public String toString()
{
return "RowMutation(" +
"key='" + key_ + '\'' +
", modifications=[" + StringUtils.join(modifications_.values(), ", ") + "]" +
')';
}
}
}
class RowMutationSerializer implements ICompactSerializer<RowMutation>
{
private void freezeTheMaps(Map<String, ColumnFamily> map, DataOutputStream dos) throws IOException
{
int size = map.size();
private void freezeTheMaps(Map<String, ColumnFamily> map, DataOutputStream dos) throws IOException
{
int size = map.size();
dos.writeInt(size);
if (size > 0)
{
if ( size > 0 )
{
Set<String> keys = map.keySet();
for (String key : keys)
{
dos.writeUTF(key);
for( String key : keys )
{
dos.writeUTF(key);
ColumnFamily cf = map.get(key);
if (cf != null)
if ( cf != null )
{
ColumnFamily.serializer().serialize(cf, dos);
}
}
}
}
}
public void serialize(RowMutation rm, DataOutputStream dos) throws IOException
{
dos.writeUTF(rm.table());
dos.writeUTF(rm.key());
/* serialize the modifications_ in the mutation */
}
public void serialize(RowMutation rm, DataOutputStream dos) throws IOException
{
dos.writeUTF(rm.table());
dos.writeUTF(rm.key());
/* serialize the modifications_ in the mutation */
freezeTheMaps(rm.modifications_, dos);
}
private Map<String, ColumnFamily> defreezeTheMaps(DataInputStream dis) throws IOException
{
Map<String, ColumnFamily> map = new HashMap<String, ColumnFamily>();
/* serialize the deletions_ in the mutation */
freezeTheMaps(rm.deletions_, dos);
}
private Map<String, ColumnFamily> defreezeTheMaps(DataInputStream dis) throws IOException
{
Map<String, ColumnFamily> map = new HashMap<String, ColumnFamily>();
int size = dis.readInt();
for (int i = 0; i < size; ++i)
for ( int i = 0; i < size; ++i )
{
String key = dis.readUTF();
String key = dis.readUTF();
ColumnFamily cf = ColumnFamily.serializer().deserialize(dis);
map.put(key, cf);
map.put(key, cf);
}
return map;
}
}
public RowMutation deserialize(DataInputStream dis) throws IOException
{
String table = dis.readUTF();
String key = dis.readUTF();
Map<String, ColumnFamily> modifications = defreezeTheMaps(dis);
return new RowMutation(table, key, modifications);
String table = dis.readUTF();
String key = dis.readUTF();
/* Defreeze the modifications_ map */
Map<String, ColumnFamily> modifications = defreezeTheMaps(dis);
/* Defreeze the deletions_ map */
Map<String, ColumnFamily> deletions = defreezeTheMaps(dis);
return new RowMutation(table, key, modifications, deletions);
}
}

View File

@ -46,14 +46,18 @@ public class RowMutationVerbHandler implements IVerbHandler
protected Row row_ = new Row();
protected DataInputBuffer buffer_ = new DataInputBuffer();
}
private static Logger logger_ = Logger.getLogger(RowMutationVerbHandler.class);
private static Logger logger_ = Logger.getLogger(RowMutationVerbHandler.class);
/* We use this so that we can reuse the same row mutation context for the mutation. */
private static ThreadLocal<RowMutationContext> tls_ = new InheritableThreadLocal<RowMutationContext>();
public void doVerb(Message message)
{
byte[] bytes = (byte[]) message.getMessageBody()[0];
/* For DEBUG only. Printing queue length */
logger_.info( "ROW MUTATION STAGE: " + StageManager.getStageTaskCount(StorageService.mutationStage_) );
/* END DEBUG */
byte[] bytes = (byte[])message.getMessageBody()[0];
/* Obtain a Row Mutation Context from TLS */
RowMutationContext rowMutationCtx = tls_.get();
if ( rowMutationCtx == null )
@ -61,47 +65,51 @@ public class RowMutationVerbHandler implements IVerbHandler
rowMutationCtx = new RowMutationContext();
tls_.set(rowMutationCtx);
}
rowMutationCtx.buffer_.reset(bytes, bytes.length);
rowMutationCtx.buffer_.reset(bytes, bytes.length);
try
{
RowMutation rm = RowMutation.serializer().deserialize(rowMutationCtx.buffer_);
logger_.debug("Applying " + rm);
RowMutationMessage rmMsg = RowMutationMessage.serializer().deserialize(rowMutationCtx.buffer_);
RowMutation rm = rmMsg.getRowMutation();
/* Check if there were any hints in this message */
byte[] hintedBytes = message.getHeader(RowMutation.HINT);
byte[] hintedBytes = message.getHeader(RowMutationMessage.hint_);
if ( hintedBytes != null && hintedBytes.length > 0 )
{
EndPoint hint = EndPoint.fromBytes(hintedBytes);
logger_.debug("Adding hint for " + hint);
/* add necessary hints to this mutation */
RowMutation hintedMutation = new RowMutation(rm.table(), HintedHandOffManager.key_);
hintedMutation.addHints(rm.key() + ":" + hint.getHost());
hintedMutation.apply();
try
{
RowMutation hintedMutation = new RowMutation(rm.table(), HintedHandOffManager.key_);
hintedMutation.addHints(rm.key() + ":" + hint.getHost());
hintedMutation.apply();
}
catch ( ColumnFamilyNotDefinedException ex )
{
logger_.debug(LogUtil.throwableToString(ex));
}
}
long start = System.currentTimeMillis();
rowMutationCtx.row_.clear();
long start = System.currentTimeMillis();
rowMutationCtx.row_.key(rm.key());
rm.apply(rowMutationCtx.row_);
long end = System.currentTimeMillis();
WriteResponse response = new WriteResponse(rm.table(), rm.key(), true);
Message responseMessage = WriteResponse.makeWriteResponseMessage(message, response);
logger_.debug("Mutation applied in " + (end - start) + "ms. Sending response to " + message.getFrom() + " for key :" + rm.key());
MessagingService.getMessagingInstance().sendOneWay(responseMessage, message.getFrom());
}
catch(ColumnFamilyNotDefinedException ex)
long end = System.currentTimeMillis();
logger_.info("ROW MUTATION APPLY: " + (end - start) + " ms.");
/*WriteResponseMessage writeResponseMessage = new WriteResponseMessage(rm.table(), rm.key(), true);
Message response = message.getReply( StorageService.getLocalStorageEndPoint(), new Object[]{writeResponseMessage} );
logger_.debug("Sending teh response to " + message.getFrom() + " for key :" + rm.key());
MessagingService.getMessagingInstance().sendOneWay(response, message.getFrom()); */
}
catch( ColumnFamilyNotDefinedException ex )
{
// TODO shouldn't this be checked before it's sent to us?
logger_.warn("column family not defined, and no way to tell the client", ex);
}
catch (IOException e)
logger_.debug(LogUtil.throwableToString(ex));
}
catch ( IOException e )
{
logger_.error("Error in row mutation", e);
}
logger_.debug(LogUtil.throwableToString(e));
}
}
}

View File

@ -0,0 +1,178 @@
/**
* 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.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Queue;
import org.apache.log4j.Logger;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.continuations.Suspendable;
import org.apache.cassandra.db.ColumnFamilyNotDefinedException;
import org.apache.cassandra.db.ColumnFamilyStore;
import org.apache.cassandra.db.FileStruct;
import org.apache.cassandra.db.IScanner;
import org.apache.cassandra.db.Row;
import org.apache.cassandra.db.Table;
import org.apache.cassandra.io.DataInputBuffer;
import org.apache.cassandra.io.SSTable;
import org.apache.cassandra.io.SequenceFile;
import org.apache.cassandra.net.EndPoint;
import org.apache.cassandra.net.IAsyncResult;
import org.apache.cassandra.net.Message;
import org.apache.cassandra.net.MessagingService;
import org.apache.cassandra.service.StorageService;
import org.apache.cassandra.utils.LogUtil;
/**
* This class is used to scan through all the keys in disk
* in Iterator style. Usage is as follows:
* SequentialScanner scanner = new SequentialScanner("table");
*
* while ( scanner.hasNext() )
* {
* Row row = scanner.next();
* // Do something with the row
* }
*
* @author alakshman
*
*/
public class SequentialScanner implements IScanner<Row>
{
private static Logger logger_ = Logger.getLogger( SequentialScanner.class );
private final static int bufSize_ = 1024*1024;
/* Table over which we want to perform a sequential scan. */
private String table_;
private Queue<FileStruct> fsQueue_ = new PriorityQueue<FileStruct>();
public SequentialScanner(String table) throws IOException
{
table_ = table;
List<String> allFiles = Table.open(table_).getAllSSTablesOnDisk();
for (String file : allFiles)
{
FileStruct fs = new FileStruct(file, SequentialScanner.bufSize_);
fsQueue_.add(fs);
}
}
/**
* Determines if there is anything more to be
* scanned.
* @return true if more elements are remanining
* else false.
*/
public boolean hasNext() throws IOException
{
boolean hasNext = ( fsQueue_.size() > 0 ) ? true : false;
return hasNext;
}
/**
* Returns the next row associated with the smallest key
* on disk.
*
* @return row of the next smallest key on disk.
*/
public Row next() throws IOException
{
if ( fsQueue_.size() == 0 )
throw new IllegalStateException("Nothing in the stream to scan.");
Row row = null;
FileStruct fs = fsQueue_.poll();
// Process the key only if it is in the primary range and not a block index.
if ( StorageService.instance().isPrimary(fs.getKey()) && !fs.getKey().equals(SSTable.blockIndexKey_) )
{
row = Table.open(table_).get(fs.getKey());
}
doCorrections(fs.getKey());
long bytesRead = fs.advance();
if ( bytesRead != -1L )
fsQueue_.add(fs);
return row;
}
/**
* This method advances the pointer in the file struct
* in the even the same key occurs in multiple files.
*
* @param key key we are interested in.
* @throws IOException
*/
private void doCorrections(String key) throws IOException
{
List<FileStruct> lfs = new ArrayList<FileStruct>();
Iterator<FileStruct> it = fsQueue_.iterator();
while ( it.hasNext() )
{
FileStruct fs = it.next();
/*
* We encountered a key that is greater
* than the key we are currently serving
* so scram.
*/
if ( fs.getKey().compareTo(key) != 0 )
{
break;
}
else
{
lfs.add(fs);
}
}
for ( FileStruct fs : lfs )
{
/* discard duplicate entries. */
fsQueue_.poll();
long bytesRead = fs.advance();
if ( bytesRead != -1L )
{
fsQueue_.add(fs);
}
}
}
public void close() throws IOException
{
if ( fsQueue_.size() > 0 )
{
for ( int i = 0; i < fsQueue_.size(); ++i )
{
FileStruct fs = fsQueue_.poll();
fs.close();
}
}
}
public void fetch(String key, String cf) throws IOException, ColumnFamilyNotDefinedException
{
throw new UnsupportedOperationException("This operation does not make sense in the SequentialScanner");
}
}

View File

@ -18,19 +18,21 @@
package org.apache.cassandra.db;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.Collection;
import java.util.Set;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.cassandra.utils.FBUtilities;
import org.apache.cassandra.utils.HashingSchemes;
import org.apache.cassandra.utils.LogUtil;
import org.apache.log4j.Logger;
/**
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
@ -39,17 +41,22 @@ import org.apache.cassandra.utils.FBUtilities;
public final class SuperColumn implements IColumn, Serializable
{
private static Logger logger_ = Logger.getLogger(SuperColumn.class);
private static SuperColumnSerializer serializer_ = new SuperColumnSerializer();
private static ICompactSerializer2<IColumn> serializer_;
private final static String seperator_ = ":";
static SuperColumnSerializer serializer()
static
{
serializer_ = new SuperColumnSerializer();
}
static ICompactSerializer2<IColumn> serializer()
{
return serializer_;
}
private String name_;
private EfficientBidiMap columns_ = new EfficientBidiMap(ColumnComparatorFactory.getComparator(ColumnComparatorFactory.ComparatorType.TIMESTAMP));
private long markedForDeleteAt = Long.MIN_VALUE;
private AtomicBoolean isMarkedForDelete_ = new AtomicBoolean(false);
private AtomicInteger size_ = new AtomicInteger(0);
SuperColumn()
@ -63,7 +70,7 @@ public final class SuperColumn implements IColumn, Serializable
public boolean isMarkedForDelete()
{
return markedForDeleteAt > Long.MIN_VALUE;
return isMarkedForDelete_.get();
}
public String name()
@ -76,11 +83,12 @@ public final class SuperColumn implements IColumn, Serializable
return columns_.getSortedColumns();
}
public IColumn getSubColumn(String columnName)
public IColumn getSubColumn( String columnName )
{
IColumn column = columns_.get(columnName);
assert column instanceof Column;
return column;
IColumn column = columns_.get(columnName);
if ( column instanceof SuperColumn )
throw new UnsupportedOperationException("A super column cannot hold other super columns.");
return column;
}
public int compareTo(IColumn superColumn)
@ -140,7 +148,7 @@ public final class SuperColumn implements IColumn, Serializable
return size;
}
public void remove(String columnName)
protected void remove(String columnName)
{
columns_.remove(columnName);
}
@ -168,7 +176,8 @@ public final class SuperColumn implements IColumn, Serializable
public byte[] value(String key)
{
IColumn column = columns_.get(key);
assert column instanceof Column;
if ( column instanceof SuperColumn )
throw new UnsupportedOperationException("A super column cannot hold other super columns.");
if ( column != null )
return column.value();
throw new IllegalArgumentException("Value was requested for a column that does not exist.");
@ -202,18 +211,19 @@ public final class SuperColumn implements IColumn, Serializable
* Go through each sub column if it exists then as it to resolve itself
* if the column does not exist then create it.
*/
public void putColumn(IColumn column)
public boolean putColumn(IColumn column)
{
if ( !(column instanceof SuperColumn))
throw new UnsupportedOperationException("Only Super column objects should be put here");
if( !name_.equals(column.name()))
throw new IllegalArgumentException("The name should match the name of the current column or super column");
Collection<IColumn> columns = column.getSubColumns();
for (IColumn subColumn : column.getSubColumns())
for ( IColumn subColumn : columns )
{
addColumn(subColumn.name(), subColumn);
addColumn(subColumn.name(), subColumn);
}
markedForDeleteAt = Math.max(markedForDeleteAt, column.getMarkedForDeleteAt());
return false;
}
public int getObjectCount()
@ -221,8 +231,10 @@ public final class SuperColumn implements IColumn, Serializable
return 1 + columns_.size();
}
public long getMarkedForDeleteAt() {
return markedForDeleteAt;
public void delete()
{
columns_.clear();
isMarkedForDelete_.set(true);
}
int getColumnCount()
@ -230,6 +242,21 @@ public final class SuperColumn implements IColumn, Serializable
return columns_.size();
}
public void repair(IColumn column)
{
Collection<IColumn> columns = column.getSubColumns();
for ( IColumn subColumn : columns )
{
IColumn columnInternal = columns_.get(subColumn.name());
if( columnInternal == null )
columns_.put(subColumn.name(), subColumn);
else
columnInternal.repair(subColumn);
}
}
public IColumn diff(IColumn column)
{
IColumn columnDiff = new SuperColumn(column.name());
@ -260,7 +287,7 @@ public final class SuperColumn implements IColumn, Serializable
public byte[] digest()
{
Set<IColumn> columns = columns_.getSortedColumns();
byte[] xorHash = ArrayUtils.EMPTY_BYTE_ARRAY;
byte[] xorHash = new byte[0];
if(name_ == null)
return xorHash;
xorHash = name_.getBytes();
@ -275,23 +302,23 @@ public final class SuperColumn implements IColumn, Serializable
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("SuperColumn(");
sb.append(name_);
sb.append(":");
sb.append(isMarkedForDelete());
sb.append(":");
if (isMarkedForDelete()) {
sb.append(" -delete at " + getMarkedForDeleteAt() + "-");
Collection<IColumn> columns = getSubColumns();
sb.append(columns.size());
sb.append(":");
sb.append(size());
sb.append(":");
for ( IColumn subColumn : columns )
{
sb.append(subColumn.toString());
}
sb.append(" [");
sb.append(StringUtils.join(getSubColumns(), ", "));
sb.append("])");
sb.append(":");
return sb.toString();
}
public void markForDeleteAt(long timestamp) {
this.markedForDeleteAt = timestamp;
}
}
class SuperColumnSerializer implements ICompactSerializer2<IColumn>
@ -300,7 +327,7 @@ class SuperColumnSerializer implements ICompactSerializer2<IColumn>
{
SuperColumn superColumn = (SuperColumn)column;
dos.writeUTF(superColumn.name());
dos.writeLong(superColumn.getMarkedForDeleteAt());
dos.writeBoolean(superColumn.isMarkedForDelete());
Collection<IColumn> columns = column.getSubColumns();
int size = columns.size();
@ -327,15 +354,18 @@ class SuperColumnSerializer implements ICompactSerializer2<IColumn>
private SuperColumn defreezeSuperColumn(DataInputStream dis) throws IOException
{
String name = dis.readUTF();
boolean delete = dis.readBoolean();
SuperColumn superColumn = new SuperColumn(name);
superColumn.markForDeleteAt(dis.readLong());
if ( delete )
superColumn.delete();
return superColumn;
}
public IColumn deserialize(DataInputStream dis) throws IOException
{
SuperColumn superColumn = defreezeSuperColumn(dis);
fillSuperColumn(superColumn, dis);
if ( !superColumn.isMarkedForDelete() )
fillSuperColumn(superColumn, dis);
return superColumn;
}
@ -348,11 +378,12 @@ class SuperColumnSerializer implements ICompactSerializer2<IColumn>
int size = dis.readInt();
dis.skip(size);
}
private void fillSuperColumn(IColumn superColumn, DataInputStream dis) throws IOException
{
assert dis.available() != 0;
if ( dis.available() == 0 )
return;
/* read the number of columns */
int size = dis.readInt();
/* read the size of all columns */
@ -368,12 +399,13 @@ class SuperColumnSerializer implements ICompactSerializer2<IColumn>
{
if ( dis.available() == 0 )
return null;
IColumn superColumn = defreezeSuperColumn(dis);
superColumn = filter.filter(superColumn, dis);
if(superColumn != null)
{
fillSuperColumn(superColumn, dis);
if ( !superColumn.isMarkedForDelete() )
fillSuperColumn(superColumn, dis);
return superColumn;
}
else
@ -395,29 +427,32 @@ class SuperColumnSerializer implements ICompactSerializer2<IColumn>
{
if ( dis.available() == 0 )
return null;
String[] names = RowMutation.getColumnAndColumnFamily(name);
if ( names.length == 1 )
{
IColumn superColumn = defreezeSuperColumn(dis);
if(name.equals(superColumn.name()))
{
/* read the number of columns stored */
int size = dis.readInt();
/* read the size of all columns */
dis.readInt();
IColumn column = null;
for ( int i = 0; i < size; ++i )
if ( !superColumn.isMarkedForDelete() )
{
column = Column.serializer().deserialize(dis, filter);
if(column != null)
/* read the number of columns stored */
int size = dis.readInt();
/* read the size of all columns */
dis.readInt();
IColumn column = null;
for ( int i = 0; i < size; ++i )
{
superColumn.addColumn(column.name(), column);
column = null;
if(filter.isDone())
{
break;
}
column = Column.serializer().deserialize(dis, filter);
if(column != null)
{
superColumn.addColumn(column.name(), column);
column = null;
if(filter.isDone())
{
break;
}
}
}
}
return superColumn;

View File

@ -18,13 +18,25 @@
package org.apache.cassandra.db;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import org.apache.log4j.Logger;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.dht.Range;
import org.apache.cassandra.io.DataInputBuffer;
import org.apache.cassandra.io.DataOutputBuffer;
import org.apache.cassandra.io.IFileReader;
@ -32,8 +44,9 @@ import org.apache.cassandra.io.IFileWriter;
import org.apache.cassandra.io.SequenceFile;
import org.apache.cassandra.service.StorageService;
import org.apache.cassandra.utils.LogUtil;
import org.apache.cassandra.dht.Token;
import org.apache.cassandra.dht.IPartitioner;
import org.apache.log4j.Logger;
import org.apache.cassandra.io.*;
import org.apache.cassandra.utils.*;
/**
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
@ -47,7 +60,7 @@ public class SystemTable
/* Name of the SystemTable */
public static final String name_ = "System";
/* Name of the only column family in the Table */
public static final String cfName_ = "LocationInfo";
static final String cfName_ = "LocationInfo";
/* Name of columns in this table */
static final String generation_ = "Generation";
static final String token_ = "Token";
@ -150,20 +163,19 @@ public class SystemTable
* This method is used to update the SystemTable with the
* new token.
*/
public void updateToken(Token token) throws IOException
public void updateToken(BigInteger token) throws IOException
{
IPartitioner p = StorageService.getPartitioner();
if ( systemRow_ != null )
{
Map<String, ColumnFamily> columnFamilies = systemRow_.getColumnFamilyMap();
Map<String, ColumnFamily> columnFamilies = systemRow_.getColumnFamilies();
/* Retrieve the "LocationInfo" column family */
ColumnFamily columnFamily = columnFamilies.get(SystemTable.cfName_);
long oldTokenColumnTimestamp = columnFamily.getColumn(SystemTable.token_).timestamp();
/* create the "Token" whose value is the new token. */
IColumn tokenColumn = new Column(SystemTable.token_, p.getTokenFactory().toByteArray(token), oldTokenColumnTimestamp + 1);
IColumn tokenColumn = new Column(SystemTable.token_, token.toByteArray(), oldTokenColumnTimestamp + 1);
/* replace the old "Token" column with this new one. */
logger_.debug("Replacing old token " + p.getTokenFactory().fromByteArray(columnFamily.getColumn(SystemTable.token_).value()) + " with " + token);
columnFamily.addColumn(tokenColumn);
logger_.debug("Replacing old token " + new BigInteger( columnFamily.getColumn(SystemTable.token_).value() ).toString() + " with token " + token.toString());
columnFamily.addColumn(SystemTable.token_, tokenColumn);
reset(systemRow_);
}
}
@ -183,7 +195,17 @@ public class SystemTable
{
LogUtil.init();
StorageService.instance().start();
SystemTable.openSystemTable(SystemTable.cfName_).updateToken(StorageService.token("503545744:0"));
SystemTable.openSystemTable(SystemTable.cfName_).updateToken( StorageService.hash("503545744:0") );
System.out.println("Done");
/*
BigInteger hash = StorageService.hash("304700067:0");
List<Range> ranges = new ArrayList<Range>();
ranges.add( new Range(new BigInteger("1218069462158869448693347920504606362273788442553"), new BigInteger("1092770595533781724218060956188429069")) );
if ( Range.isKeyInRanges(ranges, "304700067:0") )
{
System.out.println("Done");
}
*/
}
}

View File

@ -19,14 +19,18 @@
package org.apache.cassandra.db;
import java.util.*;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.File;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.cassandra.analytics.DBAnalyticsSource;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.continuations.Suspendable;
import org.apache.cassandra.dht.BootstrapInitiateMessage;
import org.apache.cassandra.dht.Range;
import org.apache.cassandra.io.DataInputBuffer;
@ -48,6 +52,9 @@ import org.apache.cassandra.utils.FBUtilities;
import org.apache.cassandra.utils.FileUtils;
import org.apache.cassandra.utils.LogUtil;
import org.apache.log4j.Logger;
import org.apache.cassandra.io.*;
import org.apache.cassandra.utils.*;
import org.apache.cassandra.service.*;
/**
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
@ -60,7 +67,7 @@ public class Table
* is basically the column family name and the ID associated with
* this column family. We use this ID in the Commit Log header to
* determine when a log file that has been rolled can be deleted.
*/
*/
public static class TableMetadata
{
/* Name of the column family */
@ -153,7 +160,7 @@ public class Table
cfTypeMap_.put(cf, type);
}
public boolean isEmpty()
boolean isEmpty()
{
return cfIdMap_.isEmpty();
}
@ -193,7 +200,7 @@ public class Table
return cfIdMap_.containsKey(cfName);
}
public void apply() throws IOException
void apply() throws IOException
{
String table = DatabaseDescriptor.getTables().get(0);
DataOutputBuffer bufOut = new DataOutputBuffer();
@ -454,7 +461,7 @@ public class Table
return columnFamilyStores_;
}
public ColumnFamilyStore getColumnFamilyStore(String cfName)
ColumnFamilyStore getColumnFamilyStore(String cfName)
{
return columnFamilyStores_.get(cfName);
}
@ -488,7 +495,7 @@ public class Table
for ( String cfName : cfNames )
{
ColumnFamilyStore cfStore = columnFamilyStores_.get(cfName);
sb.append(cfStore.cfStats(newLineSeparator));
sb.append(cfStore.cfStats(newLineSeparator, df));
}
int newLength = sb.toString().length();
@ -592,7 +599,7 @@ public class Table
{
ColumnFamilyStore cfStore = columnFamilyStores_.get( columnFamily );
if ( cfStore != null )
MinorCompactionManager.instance().submitMajor(cfStore, 0);
MinorCompactionManager.instance().submitMajor(cfStore, null, 0);
}
}
@ -684,6 +691,26 @@ public class Table
dbAnalyticsSource_.updateReadStatistics(timeTaken);
return row;
}
public Row getRowFromMemory(String key)
{
Row row = new Row(key);
Set<String> columnFamilies = tableMetadata_.getColumnFamilies();
long start = System.currentTimeMillis();
for ( String columnFamily : columnFamilies )
{
ColumnFamilyStore cfStore = columnFamilyStores_.get(columnFamily);
if ( cfStore != null )
{
ColumnFamily cf = cfStore.getColumnFamilyFromMemory(key, columnFamily, new IdentityFilter());
if ( cf != null )
row.addColumnFamily(cf);
}
}
long timeTaken = System.currentTimeMillis() - start;
dbAnalyticsSource_.updateReadStatistics(timeTaken);
return row;
}
/**
@ -788,18 +815,22 @@ public class Table
* Once this happens the data associated with the individual column families
* is also written to the column family store's memtable.
*/
void apply(Row row) throws IOException
{
public void apply(Row row) throws IOException
{
String key = row.key();
/* Add row to the commit log. */
long start = System.currentTimeMillis();
CommitLog.CommitLogContext cLogCtx = CommitLog.open(table_).add(row);
for (ColumnFamily columnFamily : row.getColumnFamilies())
Map<String, ColumnFamily> columnFamilies = row.getColumnFamilies();
Set<String> cNames = columnFamilies.keySet();
for ( String cName : cNames )
{
ColumnFamily columnFamily = columnFamilies.get(cName);
ColumnFamilyStore cfStore = columnFamilyStores_.get(columnFamily.name());
cfStore.apply(row.key(), columnFamily, cLogCtx);
cfStore.apply( key, columnFamily, cLogCtx);
}
row.clear();
long timeTaken = System.currentTimeMillis() - start;
dbAnalyticsSource_.updateWriteStatistics(timeTaken);
}
@ -807,7 +838,7 @@ public class Table
void applyNow(Row row) throws IOException
{
String key = row.key();
Map<String, ColumnFamily> columnFamilies = row.getColumnFamilyMap();
Map<String, ColumnFamily> columnFamilies = row.getColumnFamilies();
Set<String> cNames = columnFamilies.keySet();
for ( String cName : cNames )
@ -823,11 +854,24 @@ public class Table
Set<String> cfNames = columnFamilyStores_.keySet();
for ( String cfName : cfNames )
{
if (fRecovery) {
columnFamilyStores_.get(cfName).flushMemtableOnRecovery();
} else {
columnFamilyStores_.get(cfName).forceFlush();
}
columnFamilyStores_.get(cfName).forceFlush(fRecovery);
}
}
void delete(Row row) throws IOException
{
String key = row.key();
Map<String, ColumnFamily> columnFamilies = row.getColumnFamilies();
/* Add row to commit log */
CommitLog.open(table_).add(row);
Set<String> cNames = columnFamilies.keySet();
for ( String cName : cNames )
{
ColumnFamily columnFamily = columnFamilies.get(cName);
ColumnFamilyStore cfStore = columnFamilyStores_.get(columnFamily.name());
cfStore.delete( key, columnFamily );
}
}
@ -837,7 +881,7 @@ public class Table
/* Add row to the commit log. */
long start = System.currentTimeMillis();
Map<String, ColumnFamily> columnFamilies = row.getColumnFamilyMap();
Map<String, ColumnFamily> columnFamilies = row.getColumnFamilies();
Set<String> cNames = columnFamilies.keySet();
for ( String cName : cNames )
{
@ -858,7 +902,7 @@ public class Table
}
else if(column.timestamp() == 3)
{
cfStore.forceFlush();
cfStore.forceFlush(false);
}
else if(column.timestamp() == 4)
{
@ -876,16 +920,12 @@ public class Table
dbAnalyticsSource_.updateWriteStatistics(timeTaken);
}
public Set<String> getApplicationColumnFamilies()
public static void main(String[] args) throws Throwable
{
Set<String> set = new HashSet<String>();
for (String cfName : getColumnFamilies())
{
if (DatabaseDescriptor.isApplicationColumnFamily(cfName))
{
set.add(cfName);
}
}
return set;
StorageService service = StorageService.instance();
service.start();
Table table = Table.open("Mailbox");
Row row = table.get("35300190:1");
System.out.println( row.key() );
}
}

View File

@ -47,10 +47,7 @@ class TimeFilter implements IFilter
public ColumnFamily filter(String cf, ColumnFamily columnFamily)
{
if (columnFamily == null)
return columnFamily;
String[] values = RowMutation.getColumnAndColumnFamily(cf);
String[] values = RowMutation.getColumnAndColumnFamily(cf);
String cfName = columnFamily.name();
ColumnFamily filteredCf = new ColumnFamily(cfName);
if( values.length == 1 && !DatabaseDescriptor.getColumnType(cfName).equals("Super"))
@ -61,7 +58,7 @@ class TimeFilter implements IFilter
{
if ( column.timestamp() >= timeLimit_ )
{
filteredCf.addColumn(column);
filteredCf.addColumn(column.name(), column);
++i;
}
else
@ -85,8 +82,8 @@ class TimeFilter implements IFilter
for(IColumn column : columns)
{
SuperColumn superColumn = (SuperColumn)column;
SuperColumn filteredSuperColumn = new SuperColumn(superColumn.name());
filteredCf.addColumn(filteredSuperColumn);
SuperColumn filteredSuperColumn = new SuperColumn(superColumn.name());
filteredCf.addColumn(filteredSuperColumn.name(), filteredSuperColumn);
Collection<IColumn> subColumns = superColumn.getSubColumns();
int i = 0;
for(IColumn subColumn : subColumns)
@ -146,6 +143,6 @@ class TimeFilter implements IFilter
public DataInputBuffer next(String key, String cf, SSTable ssTable) throws IOException
{
return ssTable.next( key, cf, null, new IndexHelper.TimeRange( timeLimit_, System.currentTimeMillis() ) );
return ssTable.next( key, cf, new IndexHelper.TimeRange( timeLimit_, System.currentTimeMillis() ) );
}
}

View File

@ -0,0 +1,114 @@
/**
* 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.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlElement;
import org.apache.cassandra.io.ICompactSerializer;
import org.apache.cassandra.net.Message;
import org.apache.cassandra.net.MessagingService;
import org.apache.cassandra.service.StorageService;
/*
* This message is sent back the row mutation verb handler
* and basically specifes if the write succeeded or not for a particular
* key in a table
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
*/
public class WriteResponseMessage implements Serializable
{
private static ICompactSerializer<WriteResponseMessage> serializer_;
static
{
serializer_ = new WriteResponseMessageSerializer();
}
static ICompactSerializer<WriteResponseMessage> serializer()
{
return serializer_;
}
public static Message makeWriteResponseMessage(WriteResponseMessage writeResponseMessage) throws IOException
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream( bos );
WriteResponseMessage.serializer().serialize(writeResponseMessage, dos);
Message message = new Message(StorageService.getLocalStorageEndPoint(), MessagingService.responseStage_, MessagingService.responseVerbHandler_, new Object[]{bos.toByteArray()});
return message;
}
@XmlElement(name = "Table")
private String table_;
@XmlElement(name = "key")
private String key_;
@XmlElement(name = "Status")
private boolean status_;
private WriteResponseMessage() {
}
public WriteResponseMessage(String table, String key, boolean bVal) {
table_ = table;
key_ = key;
status_ = bVal;
}
public String table()
{
return table_;
}
public String key()
{
return key_;
}
public boolean isSuccess()
{
return status_;
}
}
class WriteResponseMessageSerializer implements ICompactSerializer<WriteResponseMessage>
{
public void serialize(WriteResponseMessage wm, DataOutputStream dos) throws IOException
{
dos.writeUTF(wm.table());
dos.writeUTF(wm.key());
dos.writeBoolean(wm.isSuccess());
}
public WriteResponseMessage deserialize(DataInputStream dis) throws IOException
{
String table = dis.readUTF();
String key = dis.readUTF();
boolean status = dis.readBoolean();
return new WriteResponseMessage(table, key, status);
}
}