This commit is contained in:
Prashant Malik 2009-03-02 07:57:22 +00:00
commit 1f91e99223
344 changed files with 74502 additions and 0 deletions

BIN
lib/JSAP-2.1.jar Normal file

Binary file not shown.

BIN
lib/activation.jar Normal file

Binary file not shown.

BIN
lib/antlr-2.7.6.jar Normal file

Binary file not shown.

BIN
lib/antlr-2.7.7.jar Normal file

Binary file not shown.

BIN
lib/antlr-3.0.1.jar Normal file

Binary file not shown.

BIN
lib/antlr-runtime-3.0.1.jar Normal file

Binary file not shown.

BIN
lib/apache-javaflow.jar Normal file

Binary file not shown.

BIN
lib/asm-all-2.2.1.jar Normal file

Binary file not shown.

BIN
lib/azul-collections.jar Normal file

Binary file not shown.

BIN
lib/commons-cli-1.1.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
lib/commons-math-1.1.jar Normal file

Binary file not shown.

BIN
lib/dsiutils-1.0.7.jar Normal file

Binary file not shown.

BIN
lib/groovy-1.5.6.jar Normal file

Binary file not shown.

BIN
lib/hadoop-core.jar Normal file

Binary file not shown.

BIN
lib/jline-0.9.94.jar Normal file

Binary file not shown.

BIN
lib/libfb303.jar Normal file

Binary file not shown.

BIN
lib/libthrift.jar Normal file

Binary file not shown.

BIN
lib/log4j-1.2.8.jar Normal file

Binary file not shown.

BIN
lib/lucene-core-2.2.0.jar Normal file

Binary file not shown.

BIN
lib/pcj.jar Normal file

Binary file not shown.

BIN
lib/stringtemplate-3.0.jar Normal file

Binary file not shown.

BIN
lib/sux4j-1.0.3.jar Normal file

Binary file not shown.

BIN
lib/zookeeper-3.0.0.jar Normal file

Binary file not shown.

View File

@ -0,0 +1,788 @@
/**
* 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.analytics;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.TreeMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.service.IComponentShutdown;
import org.apache.cassandra.service.StorageService;
import org.apache.cassandra.utils.LogUtil;
import org.apache.log4j.Logger;
/**
* Context for sending metrics to Ganglia. This class drives the entire metric collection process.
*
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com ) & Karthik Ranganathan ( kranganathan@facebook.com )
*/
public class AnalyticsContext implements IComponentShutdown
{
private static Logger logger_ = Logger.getLogger(AnalyticsContext.class);
private static final String PERIOD_PROPERTY = "period";
private static final String SERVERS_PROPERTY = "servers";
private static final String UNITS_PROPERTY = "units";
private static final String SLOPE_PROPERTY = "slope";
private static final String TMAX_PROPERTY = "tmax";
private static final String DMAX_PROPERTY = "dmax";
private static final String DEFAULT_UNITS = "";
private static final String DEFAULT_SLOPE = "both";
private static final int DEFAULT_TMAX = 60;
private static final int DEFAULT_DMAX = 0;
private static final int DEFAULT_PORT = 8649;
private static final int BUFFER_SIZE = 1500; // as per libgmond.c
private static final Map<Class,String> typeTable_ = new HashMap<Class,String>(5);
private Map<String,RecordMap> bufferedData_ = new HashMap<String,RecordMap>();
/* Keeps the MetricRecord for each abstraction that implements IAnalyticsSource */
private Map<String, MetricsRecord> recordMap_ = new HashMap<String, MetricsRecord>();
private Map<String,Object> attributeMap_ = new HashMap<String,Object>();
private Set<IAnalyticsSource> updaters = new HashSet<IAnalyticsSource>(1);
private List<InetSocketAddress> metricsServers_;
private Map<String, String> unitsTable_;
private Map<String, String> slopeTable_;
private Map<String, String> tmaxTable_;
private Map<String, String> dmaxTable_;
/* singleton instance */
private static AnalyticsContext instance_;
/* Used to lock the factory for creation of StorageService instance */
private static Lock createLock_ = new ReentrantLock();
/**
* Default period in seconds at which data is sent to the metrics system.
*/
private static final int DEFAULT_PERIOD = 5;
/**
* Port to which we should write the data.
*/
private int port_ = DEFAULT_PORT;
private Timer timer = null;
private int period_ = DEFAULT_PERIOD;
private volatile boolean isMonitoring = false;
private byte[] buffer_ = new byte[BUFFER_SIZE];
private int offset_;
private DatagramSocket datagramSocket_;
static class TagMap extends TreeMap<String,Object>
{
private static final long serialVersionUID = 3546309335061952993L;
TagMap()
{
super();
}
TagMap(TagMap orig)
{
super(orig);
}
}
static class MetricMap extends TreeMap<String,Number>
{
private static final long serialVersionUID = -7495051861141631609L;
}
static class RecordMap extends HashMap<TagMap,MetricMap>
{
private static final long serialVersionUID = 259835619700264611L;
}
static
{
typeTable_.put(String.class, "string");
typeTable_.put(Byte.class, "int8");
typeTable_.put(Short.class, "int16");
typeTable_.put(Integer.class, "int32");
typeTable_.put(Float.class, "float");
}
/**
* Creates a new instance of AnalyticsReporter
*/
public AnalyticsContext()
{
StorageService.instance().registerComponentForShutdown(this);
}
/**
* Initializes the context.
*/
public void init(String contextName, String serverSpecList)
{
String periodStr = getAttribute(PERIOD_PROPERTY);
if (periodStr != null)
{
int period = 0;
try
{
period = Integer.parseInt(periodStr);
}
catch (NumberFormatException nfe)
{
}
if (period <= 0)
{
throw new AnalyticsException("Invalid period: " + periodStr);
}
setPeriod(period);
}
metricsServers_ = parse(serverSpecList, port_);
unitsTable_ = getAttributeTable(UNITS_PROPERTY);
slopeTable_ = getAttributeTable(SLOPE_PROPERTY);
tmaxTable_ = getAttributeTable(TMAX_PROPERTY);
dmaxTable_ = getAttributeTable(DMAX_PROPERTY);
try
{
datagramSocket_ = new DatagramSocket();
}
catch (SocketException se)
{
se.printStackTrace();
}
}
/**
* Sends a record to the metrics system.
*/
public void emitRecord(String recordName, OutputRecord outRec) throws IOException
{
// emit each metric in turn
for (String metricName : outRec.getMetricNames())
{
Object metric = outRec.getMetric(metricName);
String type = (String) typeTable_.get(metric.getClass());
emitMetric(metricName, type, metric.toString());
}
}
/**
* Helper which actually writes the metric in XDR format.
*
* @param name
* @param type
* @param value
* @throws IOException
*/
private void emitMetric(String name, String type, String value) throws IOException
{
String units = getUnits(name);
int slope = getSlope(name);
int tmax = getTmax(name);
int dmax = getDmax(name);
offset_ = 0;
xdr_int(0); // metric_user_defined
xdr_string(type);
xdr_string(name);
xdr_string(value);
xdr_string(units);
xdr_int(slope);
xdr_int(tmax);
xdr_int(dmax);
for (InetSocketAddress socketAddress : metricsServers_)
{
DatagramPacket packet = new DatagramPacket(buffer_, offset_, socketAddress);
datagramSocket_.send(packet);
}
}
private String getUnits(String metricName)
{
String result = (String) unitsTable_.get(metricName);
if (result == null)
{
result = DEFAULT_UNITS;
}
return result;
}
private int getSlope(String metricName)
{
String slopeString = (String) slopeTable_.get(metricName);
if (slopeString == null)
{
slopeString = DEFAULT_SLOPE;
}
return ("zero".equals(slopeString) ? 0 : 3); // see gmetric.c
}
private int getTmax(String metricName)
{
String tmaxString = (String) tmaxTable_.get(metricName);
if (tmaxString == null)
{
return DEFAULT_TMAX;
}
else
{
return Integer.parseInt(tmaxString);
}
}
private int getDmax(String metricName)
{
String dmaxString = (String) dmaxTable_.get(metricName);
if (dmaxString == null)
{
return DEFAULT_DMAX;
}
else
{
return Integer.parseInt(dmaxString);
}
}
/**
* Puts a string into the buffer by first writing the size of the string
* as an int, followed by the bytes of the string, padded if necessary to
* a multiple of 4.
*/
private void xdr_string(String s)
{
byte[] bytes = s.getBytes();
int len = bytes.length;
xdr_int(len);
System.arraycopy(bytes, 0, buffer_, offset_, len);
offset_ += len;
pad();
}
/**
* Pads the buffer with zero bytes up to the nearest multiple of 4.
*/
private void pad()
{
int newOffset = ((offset_ + 3) / 4) * 4;
while (offset_ < newOffset)
{
buffer_[offset_++] = 0;
}
}
/**
* Puts an integer into the buffer as 4 bytes, big-endian.
*/
private void xdr_int(int i)
{
buffer_[offset_++] = (byte) ((i >> 24) & 0xff);
buffer_[offset_++] = (byte) ((i >> 16) & 0xff);
buffer_[offset_++] = (byte) ((i >> 8) & 0xff);
buffer_[offset_++] = (byte) (i & 0xff);
}
/**
* Returns the names of all the factory's attributes.
*
* @return the attribute names
*/
public String[] getAttributeNames()
{
String[] result = new String[attributeMap_.size()];
int i = 0;
// for (String attributeName : attributeMap.keySet()) {
Iterator<String> it = attributeMap_.keySet().iterator();
while (it.hasNext())
{
result[i++] = it.next();
}
return result;
}
/**
* Sets the named factory attribute to the specified value, creating it
* if it did not already exist. If the value is null, this is the same as
* calling removeAttribute.
*
* @param attributeName the attribute name
* @param value the new attribute value
*/
public void setAttribute(String attributeName, Object value)
{
attributeMap_.put(attributeName, value);
}
/**
* Removes the named attribute if it exists.
*
* @param attributeName the attribute name
*/
public void removeAttribute(String attributeName)
{
attributeMap_.remove(attributeName);
}
/**
* Returns the value of the named attribute, or null if there is no
* attribute of that name.
*
* @param attributeName the attribute name
* @return the attribute value
*/
public String getAttribute(String attributeName)
{
return (String)attributeMap_.get(attributeName);
}
/**
* Returns an attribute-value map derived from the factory attributes
* by finding all factory attributes that begin with
* <i>contextName</i>.<i>tableName</i>. The returned map consists of
* those attributes with the contextName and tableName stripped off.
*/
protected Map<String,String> getAttributeTable(String tableName)
{
String prefix = tableName + ".";
Map<String,String> result = new HashMap<String,String>();
for (String attributeName : getAttributeNames())
{
if (attributeName.startsWith(prefix))
{
String name = attributeName.substring(prefix.length());
String value = (String) getAttribute(attributeName);
result.put(name, value);
}
}
return result;
}
/**
* Starts or restarts monitoring, the emitting of metrics records.
*/
public void startMonitoring() throws IOException {
if (!isMonitoring)
{
startTimer();
isMonitoring = true;
}
}
/**
* Stops monitoring. This does not free buffered data.
* @see #close()
*/
public void stopMonitoring() {
if (isMonitoring)
{
shutdown();
isMonitoring = false;
}
}
/**
* Returns true if monitoring is currently in progress.
*/
public boolean isMonitoring() {
return isMonitoring;
}
/**
* Stops monitoring and frees buffered data, returning this
* object to its initial state.
*/
public void close()
{
stopMonitoring();
clearUpdaters();
}
/**
* Creates a new AbstractMetricsRecord instance with the given <code>recordName</code>.
* Throws an exception if the metrics implementation is configured with a fixed
* set of record names and <code>recordName</code> is not in that set.
*
* @param recordName the name of the record
* @throws AnalyticsException if recordName conflicts with configuration data
*/
public final void createRecord(String recordName)
{
if (bufferedData_.get(recordName) == null)
{
bufferedData_.put(recordName, new RecordMap());
}
recordMap_.put(recordName, new MetricsRecord(recordName, this));
}
/**
* Return the MetricsRecord associated with this record name.
* @param recordName the name of the record
* @return newly created instance of MetricsRecordImpl or subclass
*/
public MetricsRecord getMetricsRecord(String recordName)
{
return recordMap_.get(recordName);
}
/**
* Registers a callback to be called at time intervals determined by
* the configuration.
*
* @param updater object to be run periodically; it should update
* some metrics records
*/
public void registerUpdater(final IAnalyticsSource updater)
{
if (!updaters.contains(updater)) {
updaters.add(updater);
}
}
/**
* Removes a callback, if it exists.
*
* @param updater object to be removed from the callback list
*/
public void unregisterUpdater(IAnalyticsSource updater)
{
updaters.remove(updater);
}
private void clearUpdaters()
{
updaters.clear();
}
/**
* Starts timer if it is not already started
*/
private void startTimer()
{
if (timer == null)
{
timer = new Timer("Timer thread for monitoring AnalyticsContext", true);
TimerTask task = new TimerTask()
{
public void run()
{
try
{
timerEvent();
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
};
long millis = period_ * 1000;
timer.scheduleAtFixedRate(task, millis, millis);
}
}
/**
* Stops timer if it is running
*/
public void shutdown()
{
if (timer != null)
{
timer.cancel();
timer = null;
}
}
/**
* Timer callback.
*/
private void timerEvent() throws IOException
{
if (isMonitoring)
{
Collection<IAnalyticsSource> myUpdaters;
// we dont need to synchronize as there will not be any
// addition or removal of listeners
myUpdaters = new ArrayList<IAnalyticsSource>(updaters);
// Run all the registered updates without holding a lock
// on this context
for (IAnalyticsSource updater : myUpdaters)
{
try
{
updater.doUpdates(this);
}
catch (Throwable throwable)
{
throwable.printStackTrace();
}
}
emitRecords();
}
}
/**
* Emits the records.
*/
private void emitRecords() throws IOException
{
for (String recordName : bufferedData_.keySet())
{
RecordMap recordMap = bufferedData_.get(recordName);
synchronized (recordMap)
{
for (TagMap tagMap : recordMap.keySet())
{
MetricMap metricMap = recordMap.get(tagMap);
OutputRecord outRec = new OutputRecord(tagMap, metricMap);
emitRecord(recordName, outRec);
}
}
}
flush();
}
/**
* Called each period after all records have been emitted, this method does nothing.
* Subclasses may override it in order to perform some kind of flush.
*/
protected void flush() throws IOException
{
}
/**
* Called by MetricsRecordImpl.update(). Creates or updates a row in
* the internal table of metric data.
*/
protected void update(MetricsRecord record)
{
String recordName = record.getRecordName();
TagMap tagTable = record.getTagTable();
Map<String,MetricValue> metricUpdates = record.getMetricTable();
RecordMap recordMap = getRecordMap(recordName);
synchronized (recordMap)
{
MetricMap metricMap = recordMap.get(tagTable);
if (metricMap == null)
{
metricMap = new MetricMap();
TagMap tagMap = new TagMap(tagTable); // clone tags
recordMap.put(tagMap, metricMap);
}
for (String metricName : metricUpdates.keySet())
{
MetricValue updateValue = metricUpdates.get(metricName);
Number updateNumber = updateValue.getNumber();
Number currentNumber = metricMap.get(metricName);
if (currentNumber == null || updateValue.isAbsolute())
{
metricMap.put(metricName, updateNumber);
}
else
{
Number newNumber = sum(updateNumber, currentNumber);
metricMap.put(metricName, newNumber);
}
}
}
}
private RecordMap getRecordMap(String recordName)
{
return bufferedData_.get(recordName);
}
/**
* Adds two numbers, coercing the second to the type of the first.
*
*/
private Number sum(Number a, Number b)
{
if (a instanceof Integer)
{
return new Integer(a.intValue() + b.intValue());
}
else if (a instanceof Float)
{
return new Float(a.floatValue() + b.floatValue());
}
else if (a instanceof Short)
{
return new Short((short)(a.shortValue() + b.shortValue()));
}
else if (a instanceof Byte)
{
return new Byte((byte)(a.byteValue() + b.byteValue()));
}
else
{
// should never happen
throw new AnalyticsException("Invalid number type");
}
}
/**
* Called by MetricsRecordImpl.remove(). Removes any matching row in
* the internal table of metric data. A row matches if it has the same
* tag names and tag values.
*/
protected void remove(MetricsRecord record)
{
String recordName = record.getRecordName();
TagMap tagTable = record.getTagTable();
RecordMap recordMap = getRecordMap(recordName);
recordMap.remove(tagTable);
}
/**
* Returns the timer period.
*/
public int getPeriod()
{
return period_;
}
/**
* Sets the timer period
*/
protected void setPeriod(int period)
{
this.period_ = period;
}
/**
* Sets the default port to listen on
*/
public void setPort(int port)
{
port_ = port;
}
/**
* Parses a space and/or comma separated sequence of server specifications
* of the form <i>hostname</i> or <i>hostname:port</i>. If
* the specs string is null, defaults to localhost:defaultPort.
*
* @return a list of InetSocketAddress objects.
*/
private static List<InetSocketAddress> parse(String specs, int defaultPort)
{
List<InetSocketAddress> result = new ArrayList<InetSocketAddress>(1);
if (specs == null) {
result.add(new InetSocketAddress("localhost", defaultPort));
}
else {
String[] specStrings = specs.split("[ ,]+");
for (String specString : specStrings) {
int colon = specString.indexOf(':');
if (colon < 0 || colon == specString.length() - 1)
{
result.add(new InetSocketAddress(specString, defaultPort));
} else
{
String hostname = specString.substring(0, colon);
int port = Integer.parseInt(specString.substring(colon+1));
result.add(new InetSocketAddress(hostname, port));
}
}
}
return result;
}
/**
* Starts up the analytics context and registers the VM metrics.
*/
public void start()
{
// register the vm analytics object with the analytics context to update the data
registerUpdater(new VMAnalyticsSource());
init("analyticsContext", DatabaseDescriptor.getGangliaServers());
try
{
startMonitoring();
}
catch(IOException e)
{
logger_.error(LogUtil.throwableToString(e));
}
}
public void stop()
{
close();
}
/**
* Factory method that gets an instance of the StorageService
* class.
*/
public static AnalyticsContext instance()
{
if ( instance_ == null )
{
AnalyticsContext.createLock_.lock();
try
{
if ( instance_ == null )
{
instance_ = new AnalyticsContext();
}
}
finally
{
createLock_.unlock();
}
}
return instance_;
}
}

View File

@ -0,0 +1,47 @@
/**
* 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.analytics;
/**
* General-purpose, unchecked metrics exception.
*
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com ) & Karthik Ranganathan ( kranganathan@facebook.com )
*/
public class AnalyticsException extends RuntimeException
{
private static final long serialVersionUID = -1643257498540498497L;
/**
* Creates a new instance of MetricsException
*/
public AnalyticsException()
{
}
/** Creates a new instance of MetricsException
*
* @param message an error message
*/
public AnalyticsException(String message)
{
super(message);
}
}

View File

@ -0,0 +1,182 @@
/**
* 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.analytics;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
/**
* This class sets up the analytics package to report metrics into
* Ganglia for the various DB operations such as: reads per second,
* average read latency, writes per second, average write latency.
*
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com ) & Karthik Ranganathan ( kranganathan@facebook.com )
*/
public class DBAnalyticsSource implements IAnalyticsSource
{
private static final String METRIC_READ_OPS = "Read Operations";
private static final String RECORD_READ_OPS = "ReadOperationsRecord";
private static final String TAG_READOPS = "ReadOperationsTag";
private static final String TAG_READ_OPS = "ReadOperationsTagValue";
private static final String METRIC_READ_AVG = "Average Read Latency";
private static final String RECORD_READ_AVG = "ReadLatencyRecord";
private static final String TAG_READAVG = "AverageReadLatencyTag";
private static final String TAG_READ_AVG = "ReadLatencyTagValue";
private static final String METRIC_WRITE_OPS = "Write Operations";
private static final String RECORD_WRITE_OPS = "WriteOperationsRecord";
private static final String TAG_WRITEOPS = "WriteOperationsTag";
private static final String TAG_WRITE_OPS = "WriteOperationsTagValue";
private static final String METRIC_WRITE_AVG = "Average Write Latency";
private static final String RECORD_WRITE_AVG = "WriteLatencyRecord";
private static final String TAG_WRITEAVG = "AverageWriteLatencyTag";
private static final String TAG_WRITE_AVG = "WriteLatencyTagValue";
/* keep track of the number of read operations */
private AtomicInteger readOperations_ = new AtomicInteger(0);
/* keep track of the number of read latencies */
private AtomicLong readLatencies_ = new AtomicLong(0);
/* keep track of the number of write operations */
private AtomicInteger writeOperations_ = new AtomicInteger(0);
/* keep track of the number of write latencies */
private AtomicLong writeLatencies_ = new AtomicLong(0);
/**
* Create all the required records we intend to display, and
* register with the AnalyticsContext.
*/
public DBAnalyticsSource()
{
/* register with the AnalyticsContext */
AnalyticsContext.instance().registerUpdater(this);
/* set the units for the metric type */
AnalyticsContext.instance().setAttribute("units." + METRIC_READ_OPS, "r/s");
/* create the record */
AnalyticsContext.instance().createRecord(RECORD_READ_OPS);
/* set the units for the metric type */
AnalyticsContext.instance().setAttribute("units." + METRIC_READ_AVG, "ms");
/* create the record */
AnalyticsContext.instance().createRecord(RECORD_READ_AVG);
/* set the units for the metric type */
AnalyticsContext.instance().setAttribute("units." + METRIC_WRITE_OPS, "w/s");
/* create the record */
AnalyticsContext.instance().createRecord(RECORD_WRITE_OPS);
/* set the units for the metric type */
AnalyticsContext.instance().setAttribute("units." + METRIC_WRITE_AVG, "ms");
/* create the record */
AnalyticsContext.instance().createRecord(RECORD_WRITE_AVG);
}
/**
* Update each of the records with the relevant data
*
* @param context the reference to the context which has called this callback
*/
public void doUpdates(AnalyticsContext context)
{
// update the read operations record
MetricsRecord readUsageRecord = context.getMetricsRecord(RECORD_READ_OPS);
int period = context.getPeriod();
if(readUsageRecord != null)
{
if ( readOperations_.get() > 0 )
{
readUsageRecord.setTag(TAG_READOPS, TAG_READ_OPS);
readUsageRecord.setMetric(METRIC_READ_OPS, readOperations_.get() / period);
readUsageRecord.update();
}
}
// update the read latency record
MetricsRecord readLatencyRecord = context.getMetricsRecord(RECORD_READ_AVG);
if(readLatencyRecord != null)
{
if ( readOperations_.get() > 0 )
{
readLatencyRecord.setTag(TAG_READAVG, TAG_READ_AVG);
readLatencyRecord.setMetric(METRIC_READ_AVG, readLatencies_.get() / readOperations_.get() );
readLatencyRecord.update();
}
}
// update the write operations record
MetricsRecord writeUsageRecord = context.getMetricsRecord(RECORD_WRITE_OPS);
if(writeUsageRecord != null)
{
if ( writeOperations_.get() > 0 )
{
writeUsageRecord.setTag(TAG_WRITEOPS, TAG_WRITE_OPS);
writeUsageRecord.setMetric(METRIC_WRITE_OPS, writeOperations_.get() / period);
writeUsageRecord.update();
}
}
// update the write latency record
MetricsRecord writeLatencyRecord = context.getMetricsRecord(RECORD_WRITE_AVG);
if(writeLatencyRecord != null)
{
if ( writeOperations_.get() > 0 )
{
writeLatencyRecord.setTag(TAG_WRITEAVG, TAG_WRITE_AVG);
writeLatencyRecord.setMetric(METRIC_WRITE_AVG, writeLatencies_.get() / writeOperations_.get() );
writeLatencyRecord.update();
}
}
clear();
}
/**
* Reset all the metric records
*/
private void clear()
{
readOperations_.set(0);
readLatencies_.set(0);
writeOperations_.set(0);
writeLatencies_.set(0);
}
/**
* Update the read statistics.
*/
public void updateReadStatistics(long latency)
{
readOperations_.incrementAndGet();
readLatencies_.addAndGet(latency);
}
/**
* Update the write statistics.
*/
public void updateWriteStatistics(long latency)
{
writeOperations_.incrementAndGet();
writeLatencies_.addAndGet(latency);
}
}

View File

@ -0,0 +1,35 @@
/**
* 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.analytics;
/**
* Call-back interface. See <code>AnalyticsContext.registerUpdater()</code>.
* This callback is called at a regular (pre-registered time interval) in
* order to update the metric values.
*
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com ) & Karthik Ranganathan ( kranganathan@facebook.com )
*/
public interface IAnalyticsSource
{
/**
* Timer-based call-back from the metric library.
*/
public abstract void doUpdates(AnalyticsContext context);
}

View File

@ -0,0 +1,77 @@
/**
* 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.analytics;
/**
* A Number that is either an absolute or an incremental amount.
*
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com ) & Karthik Ranganathan ( kranganathan@facebook.com )
*/
public class MetricValue
{
public static final boolean ABSOLUTE = false;
public static final boolean INCREMENT = true;
private boolean isIncrement;
private Number number;
/**
* Creates a new instance of MetricValue
*
* @param number this initializes the initial value of this metric
* @param isIncrement sets if the metric can be incremented or only set
*/
public MetricValue(Number number, boolean isIncrement)
{
this.number = number;
this.isIncrement = isIncrement;
}
/**
* Checks if this metric can be incremented.
*
* @return true if the value of this metric can be incremented, false otherwise
*/
public boolean isIncrement()
{
return isIncrement;
}
/**
* Checks if the value of this metric is always an absolute value. This is the
* inverse of isIncrement.
*
* @return true if the
*/
public boolean isAbsolute()
{
return !isIncrement;
}
/**
* Returns the current number value of the metric.
*
* @return the Number value of this metric
*/
public Number getNumber()
{
return number;
}
}

View File

@ -0,0 +1,265 @@
/**
* 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.analytics;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* This class keeps a back-pointer to the AnalyticsContext
* and delegates back to it on <code>update</code> and <code>remove()</code>.
*
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com ) & Karthik Ranganathan ( kranganathan@facebook.com )
*/
public class MetricsRecord {
private AnalyticsContext.TagMap tagTable = new AnalyticsContext.TagMap();
private Map<String,MetricValue> metricTable = new LinkedHashMap<String,MetricValue>();
private String recordName;
private AnalyticsContext context;
/**
* Creates a new instance of MetricsRecord
*
* @param recordName name of this record
* @param context the context which this record is a part of
*/
protected MetricsRecord(String recordName, AnalyticsContext context)
{
this.recordName = recordName;
this.context = context;
}
/**
* Returns the record name.
*
* @return the record name
*/
public String getRecordName() {
return recordName;
}
/**
* Sets the named tag to the specified value.
*
* @param tagName name of the tag
* @param tagValue new value of the tag
* @throws MetricsException if the tagName conflicts with the configuration
*/
public void setTag(String tagName, String tagValue) {
if (tagValue == null) {
tagValue = "";
}
tagTable.put(tagName, tagValue);
}
/**
* Sets the named tag to the specified value.
*
* @param tagName name of the tag
* @param tagValue new value of the tag
* @throws MetricsException if the tagName conflicts with the configuration
*/
public void setTag(String tagName, int tagValue) {
tagTable.put(tagName, new Integer(tagValue));
}
/**
* Sets the named tag to the specified value.
*
* @param tagName name of the tag
* @param tagValue new value of the tag
* @throws MetricsException if the tagName conflicts with the configuration
*/
public void setTag(String tagName, short tagValue) {
tagTable.put(tagName, new Short(tagValue));
}
/**
* Sets the named tag to the specified value.
*
* @param tagName name of the tag
* @param tagValue new value of the tag
* @throws MetricsException if the tagName conflicts with the configuration
*/
public void setTag(String tagName, byte tagValue)
{
tagTable.put(tagName, new Byte(tagValue));
}
/**
* Sets the named metric to the specified value.
*
* @param metricName name of the metric
* @param metricValue new value of the metric
* @throws MetricsException if the metricName or the type of the metricValue
* conflicts with the configuration
*/
public void setMetric(String metricName, int metricValue)
{
setAbsolute(metricName, new Integer(metricValue));
}
/**
* Sets the named metric to the specified value.
*
* @param metricName name of the metric
* @param metricValue new value of the metric
* @throws MetricsException if the metricName or the type of the metricValue
* conflicts with the configuration
*/
public void setMetric(String metricName, short metricValue)
{
setAbsolute(metricName, new Short(metricValue));
}
/**
* Sets the named metric to the specified value.
*
* @param metricName name of the metric
* @param metricValue new value of the metric
* @throws MetricsException if the metricName or the type of the metricValue
* conflicts with the configuration
*/
public void setMetric(String metricName, byte metricValue)
{
setAbsolute(metricName, new Byte(metricValue));
}
/**
* Sets the named metric to the specified value.
*
* @param metricName name of the metric
* @param metricValue new value of the metric
* @throws MetricsException if the metricName or the type of the metricValue
* conflicts with the configuration
*/
public void setMetric(String metricName, float metricValue)
{
setAbsolute(metricName, new Float(metricValue));
}
/**
* Increments the named metric by the specified value.
*
* @param metricName name of the metric
* @param metricValue incremental value
* @throws MetricsException if the metricName or the type of the metricValue
* conflicts with the configuration
*/
public void incrMetric(String metricName, int metricValue)
{
setIncrement(metricName, new Integer(metricValue));
}
/**
* Increments the named metric by the specified value.
*
* @param metricName name of the metric
* @param metricValue incremental value
* @throws MetricsException if the metricName or the type of the metricValue
* conflicts with the configuration
*/
public void incrMetric(String metricName, short metricValue)
{
setIncrement(metricName, new Short(metricValue));
}
/**
* Increments the named metric by the specified value.
*
* @param metricName name of the metric
* @param metricValue incremental value
* @throws MetricsException if the metricName or the type of the metricValue
* conflicts with the configuration
*/
public void incrMetric(String metricName, byte metricValue)
{
setIncrement(metricName, new Byte(metricValue));
}
/**
* Increments the named metric by the specified value.
*
* @param metricName name of the metric
* @param metricValue incremental value
* @throws MetricsException if the metricName or the type of the metricValue
* conflicts with the configuration
*/
public void incrMetric(String metricName, float metricValue)
{
setIncrement(metricName, new Float(metricValue));
}
/**
* Sets the value of the metric identified by metricName with the
* number metricValue.
*
* @param metricName name of the metric
* @param metricValue number value to which it should be updated
*/
private void setAbsolute(String metricName, Number metricValue)
{
metricTable.put(metricName, new MetricValue(metricValue, MetricValue.ABSOLUTE));
}
/**
* Increments the value of the metric identified by metricName with the
* number metricValue.
*
* @param metricName name of the metric
* @param metricValue number value by which it should be incremented
*/
private void setIncrement(String metricName, Number metricValue)
{
metricTable.put(metricName, new MetricValue(metricValue, MetricValue.INCREMENT));
}
/**
* Updates the table of buffered data which is to be sent periodically.
* If the tag values match an existing row, that row is updated;
* otherwise, a new row is added.
*/
public void update()
{
context.update(this);
}
/**
* Removes the row, if it exists, in the buffered data table having tags
* that equal the tags that have been set on this record.
*/
public void remove()
{
context.remove(this);
}
AnalyticsContext.TagMap getTagTable()
{
return tagTable;
}
Map<String, MetricValue> getMetricTable()
{
return metricTable;
}
}

View File

@ -0,0 +1,82 @@
/**
* 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.analytics;
import java.util.Collections;
import java.util.Set;
/**
* Represents a record of metric data to be sent to a metrics system.
*
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com ) & Karthik Ranganathan ( kranganathan@facebook.com )
*/
public class OutputRecord
{
private AnalyticsContext.TagMap tagMap;
private AnalyticsContext.MetricMap metricMap;
/**
* Creates a new instance of OutputRecord
*/
OutputRecord(AnalyticsContext.TagMap tagMap, AnalyticsContext.MetricMap metricMap)
{
this.tagMap = tagMap;
this.metricMap = metricMap;
}
/**
* Returns the set of tag names.
*/
public Set<String> getTagNames()
{
return Collections.unmodifiableSet(tagMap.keySet());
}
/**
* Returns a tag object which is can be a String, Integer, Short or Byte.
*
* @return the tag value, or null if there is no such tag
*/
public Object getTag(String name)
{
return tagMap.get(name);
}
/**
* Returns the set of metric names.
*
* @return the set of metric names
*/
public Set<String> getMetricNames()
{
return Collections.unmodifiableSet(metricMap.keySet());
}
/**
* Returns the metric object which can be a Float, Integer, Short or Byte.
*
* @param name name of the metric for which the value is being requested
* @return return the tag value, or null if there is no such tag
*/
public Number getMetric(String name)
{
return (Number) metricMap.get(name);
}
}

View File

@ -0,0 +1,86 @@
/**
* 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.analytics;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.util.HashMap;
import java.util.Map;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.service.StorageService;
import org.apache.cassandra.utils.LogUtil;
import org.apache.log4j.Logger;
/**
* This class sets up the analytics package to report metrics into
* Ganglia for VM heap utilization.
*
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com ) & Karthik Ranganathan ( kranganathan@facebook.com )
*/
public class VMAnalyticsSource implements IAnalyticsSource
{
private static final String METRIC_MEMUSAGE = "VM Heap Utilization";
private static final String RECORD_MEMUSAGE = "MemoryUsageRecord";
private static final String TAG_MEMUSAGE = "MemoryUsageTag";
private static final String TAG_MEMUSAGE_MEMUSED = "MemoryUsedTagValue";
/**
* Setup the Ganglia record to display the VM heap utilization.
*/
public VMAnalyticsSource()
{
// set the units for the metric type
AnalyticsContext.instance().setAttribute("units." + METRIC_MEMUSAGE, "MB");
// create the record
AnalyticsContext.instance().createRecord(RECORD_MEMUSAGE);
}
/**
* Update the VM heap utilization record with the relevant data.
*
* @param context the reference to the context which has called this callback
*/
public void doUpdates(AnalyticsContext context)
{
// update the memory used record
MetricsRecord memUsageRecord = context.getMetricsRecord(RECORD_MEMUSAGE);
if(memUsageRecord != null)
{
updateUsedMemory(memUsageRecord);
}
}
private void updateUsedMemory(MetricsRecord memUsageRecord)
{
memUsageRecord.setTag(TAG_MEMUSAGE, TAG_MEMUSAGE_MEMUSED);
memUsageRecord.setMetric(METRIC_MEMUSAGE, getMemoryUsed());
memUsageRecord.update();
}
private float getMemoryUsed()
{
MemoryMXBean memoryMxBean = ManagementFactory.getMemoryMXBean();
MemoryUsage memUsage = memoryMxBean.getHeapMemoryUsage();
return (float)memUsage.getUsed()/(1024 * 1024);
}
}

View File

@ -0,0 +1,234 @@
/**
* 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.
*/
//
// ANTLR Grammar for the Cassandra Command Line Interface (CLI).
//
// Note: This grammar handles all but the CQL statements. CQL
// statements are detected separately (based on the first token)
// and directly sent to server-side for processing.
//
grammar Cli;
options {
output=AST;
ASTLabelType=CommonTree;
backtrack=true;
}
//
// Nodes in the AST
//
tokens {
//
// Top-level nodes. These typically correspond to
// various top-level CLI statements.
//
NODE_CONNECT;
NODE_DESCRIBE_TABLE;
NODE_EXIT;
NODE_HELP;
NODE_NO_OP;
NODE_SHOW_CLUSTER_NAME;
NODE_SHOW_CONFIG_FILE;
NODE_SHOW_VERSION;
NODE_SHOW_TABLES;
NODE_THRIFT_GET;
NODE_THRIFT_SET;
// Internal Nodes.
NODE_COLUMN_ACCESS;
NODE_ID_LIST;
}
@parser::header {
package com.facebook.infrastructure.cli;
}
@lexer::header {
package com.facebook.infrastructure.cli;
}
//
// Parser Section
//
// the root node
root: stmt SEMICOLON? EOF -> stmt;
stmt
: connectStmt
| exitStmt
| describeTable
| getStmt
| helpStmt
| setStmt
| showStmt
| -> ^(NODE_NO_OP)
;
connectStmt
: K_CONNECT host SLASH port -> ^(NODE_CONNECT host port)
;
helpStmt
: K_HELP -> ^(NODE_HELP)
| '?' -> ^(NODE_HELP)
;
exitStmt
: K_QUIT -> ^(NODE_EXIT)
| K_EXIT -> ^(NODE_EXIT)
;
getStmt
: K_THRIFT K_GET columnFamilyExpr -> ^(NODE_THRIFT_GET columnFamilyExpr)
;
setStmt
: K_THRIFT K_SET columnFamilyExpr '=' value -> ^(NODE_THRIFT_SET columnFamilyExpr value)
;
showStmt
: showClusterName
| showVersion
| showConfigFile
| showTables
;
showClusterName
: K_SHOW K_CLUSTER K_NAME -> ^(NODE_SHOW_CLUSTER_NAME)
;
showConfigFile
: K_SHOW K_CONFIG K_FILE -> ^(NODE_SHOW_CONFIG_FILE)
;
showVersion
: K_SHOW K_VERSION -> ^(NODE_SHOW_VERSION)
;
showTables
: K_SHOW K_TABLES -> ^(NODE_SHOW_TABLES)
;
describeTable
: K_DESCRIBE K_TABLE table -> ^(NODE_DESCRIBE_TABLE table);
columnFamilyExpr
: table DOT columnFamily '[' rowKey ']'
( '[' a+=columnOrSuperColumn ']'
('[' a+=columnOrSuperColumn ']')?
)?
-> ^(NODE_COLUMN_ACCESS table columnFamily rowKey ($a+)?)
;
table: Identifier;
columnFamily: Identifier;
rowKey: StringLiteral;
value: StringLiteral;
columnOrSuperColumn: StringLiteral;
host: id+=Identifier (id+=DOT id+=Identifier)* -> ^(NODE_ID_LIST $id+);
port: IntegerLiteral;
//
// Lexer Section
//
//
// Keywords (in alphabetical order for convenience)
//
// CLI is case-insensitive with respect to these keywords.
// However, they MUST be listed in upper case here.
//
K_CONFIG: 'CONFIG';
K_CONNECT: 'CONNECT';
K_CLUSTER: 'CLUSTER';
K_DESCRIBE: 'DESCRIBE';
K_GET: 'GET';
K_HELP: 'HELP';
K_EXIT: 'EXIT';
K_FILE: 'FILE';
K_NAME: 'NAME';
K_QUIT: 'QUIT';
K_SET: 'SET';
K_SHOW: 'SHOW';
K_TABLE: 'TABLE';
K_TABLES: 'TABLES';
K_THRIFT: 'THRIFT';
K_VERSION: 'VERSION';
// private syntactic rules
fragment
Letter
: 'a'..'z'
| 'A'..'Z'
;
fragment
Digit
: '0'..'9'
;
// syntactic Elements
Identifier
: Letter ( Letter | Digit | '_')*
;
// literals
StringLiteral
:
'\'' (~'\'')* '\'' ( '\'' (~'\'')* '\'' )*
;
IntegerLiteral
: Digit+;
//
// syntactic elements
//
DOT
: '.'
;
SLASH
: '/'
;
SEMICOLON
: ';'
;
WS
: (' '|'\r'|'\t'|'\n') {$channel=HIDDEN;} // whitepace
;
COMMENT
: '--' (~('\n'|'\r'))* { $channel=HIDDEN; }
| '/*' (options {greedy=false;} : .)* '*/' { $channel=HIDDEN; }
;

View File

@ -0,0 +1,43 @@
NODE_SHOW_CONFIG_FILE=10
K_TABLES=32
K_VERSION=31
K_EXIT=22
NODE_EXIT=6
K_FILE=30
K_GET=24
K_CONNECT=18
K_CONFIG=29
SEMICOLON=17
Digit=40
Identifier=36
NODE_THRIFT_GET=13
K_SET=25
StringLiteral=37
NODE_HELP=7
NODE_NO_OP=8
NODE_THRIFT_SET=14
K_DESCRIBE=33
NODE_SHOW_VERSION=11
NODE_ID_LIST=16
WS=41
NODE_CONNECT=4
SLASH=19
K_THRIFT=23
NODE_SHOW_TABLES=12
K_CLUSTER=27
K_HELP=20
K_SHOW=26
NODE_DESCRIBE_TABLE=5
K_TABLE=34
IntegerLiteral=38
NODE_SHOW_CLUSTER_NAME=9
COMMENT=42
DOT=35
K_NAME=28
Letter=39
NODE_COLUMN_ACCESS=15
K_QUIT=21
'?'=43
'='=44
'['=45
']'=46

View File

@ -0,0 +1,323 @@
/**
* 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.cli;
import com.facebook.thrift.*;
import org.antlr.runtime.tree.*;
import org.apache.cassandra.cql.common.Utils;
import org.apache.cassandra.service.Cassandra;
import org.apache.cassandra.service.CassandraException;
import org.apache.cassandra.service.CqlResult_t;
import org.apache.cassandra.service.column_t;
import org.apache.cassandra.service.Cassandra.Client;
import org.apache.cassandra.utils.LogUtil;
import java.util.*;
// Cli Client Side Library
public class CliClient
{
private Cassandra.Client thriftClient_ = null;
private CliSessionState css_ = null;
public CliClient(CliSessionState css, Cassandra.Client thriftClient)
{
css_ = css;
thriftClient_ = thriftClient;
}
// Execute a CLI Statement
public void executeCLIStmt(String stmt) throws TException
{
CommonTree ast = null;
ast = CliCompiler.compileQuery(stmt);
switch (ast.getType()) {
case CliParser.NODE_EXIT:
cleanupAndExit();
break;
case CliParser.NODE_THRIFT_GET:
executeGet(ast);
break;
case CliParser.NODE_HELP:
printCmdHelp();
break;
case CliParser.NODE_THRIFT_SET:
executeSet(ast);
break;
case CliParser.NODE_SHOW_CLUSTER_NAME:
executeShowProperty(ast, "cluster name");
break;
case CliParser.NODE_SHOW_CONFIG_FILE:
executeShowProperty(ast, "config file");
break;
case CliParser.NODE_SHOW_VERSION:
executeShowProperty(ast, "version");
break;
case CliParser.NODE_SHOW_TABLES:
executeShowTables(ast);
break;
case CliParser.NODE_DESCRIBE_TABLE:
executeDescribeTable(ast);
break;
case CliParser.NODE_CONNECT:
executeConnect(ast);
break;
case CliParser.NODE_NO_OP:
// comment lines come here; they are treated as no ops.
break;
default:
css_.err.println("Invalid Statement (Type: " + ast.getType() + ")");
break;
}
}
private void printCmdHelp()
{
css_.out.println("List of all CLI commands:");
css_.out.println("? Same as help.");
css_.out.println("connect <hostname>/<port> Connect to Cassandra's thrift service.");
css_.out.println("describe table <tbl> Describe table.");
css_.out.println("exit Exit CLI.");
css_.out.println("explain plan [<set stmt>|<get stmt>|<select stmt>] Explains the PLAN for specified stmt.");
css_.out.println("help Display this help.");
css_.out.println("quit Exit CLI.");
css_.out.println("show config file Display contents of config file");
css_.out.println("show cluster name Display cassandra server version");
css_.out.println("show tables Show list of tables.");
css_.out.println("show version Show server version.");
css_.out.println("select ... CQL select statement (TBD).");
css_.out.println("get ... CQL data retrieval statement.");
css_.out.println("set ... CQL DML statement.");
css_.out.println("thrift get <tbl>.<cf>['<rowKey>'] (will be deprecated)");
css_.out.println("thrift get <tbl>.<cf>['<rowKey>']['<colKey>'] (will be deprecated)");
css_.out.println("thrift set <tbl>.<cf>['<rowKey>']['<colKey>'] = '<value>' (will be deprecated)");
}
private void cleanupAndExit()
{
CliMain.disconnect();
System.exit(0);
}
// Execute GET statement
private void executeGet(CommonTree ast) throws TException
{
if (!CliMain.isConnected())
return;
int childCount = ast.getChildCount();
assert(childCount == 1);
CommonTree columnFamilySpec = (CommonTree)ast.getChild(0);
assert(columnFamilySpec.getType() == CliParser.NODE_COLUMN_ACCESS);
String tableName = CliCompiler.getTableName(columnFamilySpec);
String key = CliCompiler.getKey(columnFamilySpec);
String columnFamily = CliCompiler.getColumnFamily(columnFamilySpec);
int columnSpecCnt = CliCompiler.numColumnSpecifiers(columnFamilySpec);
// assume simple columnFamily for now
if (columnSpecCnt == 0)
{
// table.cf['key']
List<column_t> columns = new ArrayList<column_t>();
try
{
columns = thriftClient_.get_slice(tableName, key, columnFamily, -1, 1000000);
}
catch(CassandraException cex)
{
css_.out.println(LogUtil.throwableToString(cex));
}
int size = columns.size();
for (Iterator<column_t> colIter = columns.iterator(); colIter.hasNext(); )
{
column_t col = colIter.next();
css_.out.printf(" (column=%s, value=%s; timestamp=%d)\n",
col.columnName, col.value, col.timestamp);
}
css_.out.println("Returned " + size + " rows.");
}
else if (columnSpecCnt == 1)
{
// table.cf['key']['column']
String columnName = CliCompiler.getColumn(columnFamilySpec, 0);
column_t col = new column_t();
try
{
col = thriftClient_.get_column(tableName, key, columnFamily + ":" + columnName);
}
catch(CassandraException cex)
{
css_.out.println(LogUtil.throwableToString(cex));
}
css_.out.printf("==> (name=%s, value=%s; timestamp=%d)\n",
col.columnName, col.value, col.timestamp);
}
else
{
assert(false);
}
}
// Execute SET statement
private void executeSet(CommonTree ast) throws TException
{
if (!CliMain.isConnected())
return;
int childCount = ast.getChildCount();
assert(childCount == 2);
CommonTree columnFamilySpec = (CommonTree)ast.getChild(0);
assert(columnFamilySpec.getType() == CliParser.NODE_COLUMN_ACCESS);
String tableName = CliCompiler.getTableName(columnFamilySpec);
String key = CliCompiler.getKey(columnFamilySpec);
String columnFamily = CliCompiler.getColumnFamily(columnFamilySpec);
int columnSpecCnt = CliCompiler.numColumnSpecifiers(columnFamilySpec);
String value = Utils.unescapeSQLString(ast.getChild(1).getText());
// assume simple columnFamily for now
if (columnSpecCnt == 1)
{
// We have the table.cf['key']['column'] = 'value' case.
// get the column name
String columnName = CliCompiler.getColumn(columnFamilySpec, 0);
// do the insert
thriftClient_.insert(tableName, key, columnFamily + ":" + columnName,
value, System.currentTimeMillis());
css_.out.println("Value inserted.");
}
else
{
/* for now (until we support batch sets) */
assert(false);
}
}
private void executeShowProperty(CommonTree ast, String propertyName) throws TException
{
if (!CliMain.isConnected())
return;
String propertyValue = thriftClient_.getStringProperty(propertyName);
css_.out.println(propertyValue);
return;
}
// process "show tables" statement
private void executeShowTables(CommonTree ast) throws TException
{
if (!CliMain.isConnected())
return;
List<String> tables = thriftClient_.getStringListProperty("tables");
for (String table : tables)
{
css_.out.println(table);
}
}
// process a statement of the form: describe table <tablename>
private void executeDescribeTable(CommonTree ast) throws TException
{
if (!CliMain.isConnected())
return;
// Get table name
int childCount = ast.getChildCount();
assert(childCount == 1);
String tableName = ast.getChild(0).getText();
// Describe and display
String describe = thriftClient_.describeTable(tableName);
css_.out.println(describe);
return;
}
// process a statement of the form: connect hostname/port
private void executeConnect(CommonTree ast) throws TException
{
int portNumber = Integer.parseInt(ast.getChild(1).getText());
Tree idList = ast.getChild(0);
StringBuffer hostName = new StringBuffer();
int idCount = idList.getChildCount();
for (int idx = 0; idx < idCount; idx++)
{
hostName.append(idList.getChild(idx).getText());
}
// disconnect current connection, if any.
// This is a no-op, if you aren't currently connected.
CliMain.disconnect();
// now, connect to the newly specified host name and port
css_.hostName = hostName.toString();
css_.thriftPort = portNumber;
CliMain.connect(css_.hostName, css_.thriftPort);
}
// execute CQL query on server
public void executeQueryOnServer(String query) throws TException
{
if (!CliMain.isConnected())
return;
CqlResult_t result = thriftClient_.executeQuery(query);
if (result == null)
{
css_.out.println("Unexpected error. Received null result from server.");
return;
}
if ((result.errorTxt != null) || (result.errorCode != 0))
{
css_.out.println("Error: " + result.errorTxt);
}
else
{
List<Map<String, String>> rows = result.resultSet;
if (rows != null)
{
for (Map<String, String> row : rows)
{
for (Iterator<Map.Entry<String, String>> it = row.entrySet().iterator(); it.hasNext(); )
{
Map.Entry<String, String> entry = it.next();
String key = entry.getKey();
String value = entry.getValue();
css_.out.print(key + " = " + value + "; ");
}
css_.out.println();
}
}
css_.out.println("Statement processed.");
}
}
}

View File

@ -0,0 +1,123 @@
/**
* 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.cli;
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.apache.cassandra.cql.common.Utils;
public class CliCompiler
{
// ANTLR does not provide case-insensitive tokenization support
// out of the box. So we override the LA (lookahead) function
// of the ANTLRStringStream class. Note: This doesn't change the
// token text-- but just relaxes the matching rules to match
// in upper case. [Logic borrowed from Hive code.]
//
// Also see discussion on this topic in:
// http://www.antlr.org/wiki/pages/viewpage.action?pageId=1782.
public static class ANTLRNoCaseStringStream extends ANTLRStringStream
{
public ANTLRNoCaseStringStream(String input)
{
super(input);
}
public int LA(int i)
{
int returnChar = super.LA(i);
if (returnChar == CharStream.EOF)
{
return returnChar;
}
else if (returnChar == 0)
{
return returnChar;
}
return Character.toUpperCase((char)returnChar);
}
}
public static CommonTree compileQuery(String query)
{
CommonTree queryTree = null;
try
{
ANTLRStringStream input = new ANTLRNoCaseStringStream(query);
CliLexer lexer = new CliLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
CliParser parser = new CliParser(tokens);
// start parsing...
queryTree = (CommonTree)(parser.root().getTree());
// semantic analysis if any...
// [tbd]
}
catch(Exception e)
{
System.err.println("Exception " + e.getMessage());
e.printStackTrace(System.err);
}
return queryTree;
}
/*
* NODE_COLUMN_ACCESS related functions.
*/
public static String getTableName(CommonTree astNode)
{
assert(astNode.getType() == CliParser.NODE_COLUMN_ACCESS);
return astNode.getChild(0).getText();
}
public static String getColumnFamily(CommonTree astNode)
{
assert(astNode.getType() == CliParser.NODE_COLUMN_ACCESS);
return astNode.getChild(1).getText();
}
public static String getKey(CommonTree astNode)
{
assert(astNode.getType() == CliParser.NODE_COLUMN_ACCESS);
return Utils.unescapeSQLString(astNode.getChild(2).getText());
}
public static int numColumnSpecifiers(CommonTree astNode)
{
// Skip over table, column family and rowKey
return astNode.getChildCount() - 3;
}
// Returns the pos'th (0-based index) column specifier in the astNode
public static String getColumn(CommonTree astNode, int pos)
{
// Skip over table, column family and rowKey
return Utils.unescapeSQLString(astNode.getChild(pos + 3).getText());
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,190 @@
/**
* 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.cli;
import com.facebook.thrift.protocol.TBinaryProtocol;
import com.facebook.thrift.transport.TSocket;
import com.facebook.thrift.transport.TTransport;
import jline.*;
import java.io.*;
import java.util.*;
import org.apache.cassandra.service.Cassandra;
//
// Cassandra Command Line Interface (CLI) Main
//
public class CliMain
{
public final static String PROMPT = "cassandra";
public final static String HISTORYFILE = ".cassandra.history";
private static TTransport transport_ = null;
private static Cassandra.Client thriftClient_ = null;
private static CliSessionState css_ = new CliSessionState();
private static CliClient cliClient_;
// Establish a thrift connection to cassandra instance
public static void connect(String server, int port)
{
TSocket socket = new TSocket(server, port);
if (transport_ != null)
transport_.close();
transport_ = socket;
TBinaryProtocol binaryProtocol = new TBinaryProtocol(transport_, false, false);
Cassandra.Client cassandraClient = new Cassandra.Client(binaryProtocol);
try
{
transport_.open();
}
catch(Exception e)
{
// Should move this to Log4J as well probably...
System.err.println("Exception " + e.getMessage());
e.printStackTrace();
}
thriftClient_ = cassandraClient;
cliClient_ = new CliClient(css_, thriftClient_);
css_.out.printf("Connected to %s/%d\n", server, port);
}
// Disconnect thrift connection to cassandra instance
public static void disconnect()
{
if (transport_ != null)
{
transport_.close();
transport_ = null;
}
}
private static void printBanner()
{
css_.out.println("Welcome to cassandra CLI.\n");
css_.out.println("Type 'help' or '?' for help. Type 'quit' or 'exit' to quit.");
}
public static boolean isConnected()
{
if (thriftClient_ == null)
{
css_.out.println("Not connected to a cassandra instance.");
return false;
}
return true;
}
private static void processServerQuery(String query)
{
if (!isConnected())
return;
try
{
cliClient_.executeQueryOnServer(query);
}
catch(Exception e)
{
System.err.println("Exception " + e.getMessage());
e.printStackTrace(System.err);
}
return;
}
private static void processCLIStmt(String query)
{
try
{
cliClient_.executeCLIStmt(query);
}
catch(Exception e)
{
System.err.println("Exception " + e.getMessage());
e.printStackTrace(System.err);
}
return;
}
private static void processLine(String line)
{
StringTokenizer tokenizer = new StringTokenizer(line);
if (tokenizer.hasMoreTokens())
{
// Use first token for now to determine if this statement is
// a CQL statement. Technically, the line could start with
// a comment token followed by a CQL statement. That case
// isn't handled right now.
String token = tokenizer.nextToken().toUpperCase();
if (token.startsWith("GET")
|| token.startsWith("SELECT")
|| token.startsWith("SET")
|| token.startsWith("DELETE")
|| token.startsWith("EXPLAIN")) // explain plan statement
{
// these are CQL Statements that are compiled and executed on server-side
processServerQuery(line);
}
else
{
// These are CLI statements processed locally
processCLIStmt(line);
}
}
}
public static void main(String args[]) throws IOException
{
// process command line args
CliOptions cliOptions = new CliOptions();
cliOptions.processArgs(css_, args);
// connect to cassandra server if host argument specified.
if (css_.hostName != null)
{
connect(css_.hostName, css_.thriftPort);
}
else
{
// If not, client must connect explicitly using the "connect" CLI statement.
cliClient_ = new CliClient(css_, null);
}
ConsoleReader reader = new ConsoleReader();
reader.setBellEnabled(false);
String historyFile = System.getProperty("user.home") + File.separator + HISTORYFILE;
reader.setHistory(new History(new File(historyFile)));
printBanner();
String line;
while ((line = reader.readLine(PROMPT+"> ")) != null)
{
processLine(line);
}
}
}

View File

@ -0,0 +1,91 @@
/**
* 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.cli;
import org.apache.commons.cli.*;
public class CliOptions {
private static Options options = null; // Info about command line options
private CommandLine cmd = null; // Command Line arguments
// Command line options
private static final String HOST_OPTION = "host";
private static final String PORT_OPTION = "port";
// Default values for optional command line arguments
private static final int DEFAULT_THRIFT_PORT = 9160;
// Register the command line options and their properties (such as
// whether they take an extra argument, etc.
static
{
options = new Options();
options.addOption(HOST_OPTION, true, "cassandra server's host name");
options.addOption(PORT_OPTION, true, "cassandra server's thrift port");
}
private static void printUsage()
{
System.err.println("");
System.err.println("Usage: cascli --host hostname [--port <portname>]");
System.err.println("");
}
public void processArgs(CliSessionState css, String[] args)
{
CommandLineParser parser = new PosixParser();
try
{
cmd = parser.parse(options, args);
}
catch (ParseException e)
{
printUsage();
e.printStackTrace();
System.exit(1);
}
if (!cmd.hasOption(HOST_OPTION))
{
// host name not specified in command line.
// In this case, we don't implicitly connect at CLI startup. In this case,
// the user must use the "connect" CLI statement to connect.
//
css.hostName = null;
// HelpFormatter formatter = new HelpFormatter();
// formatter.printHelp("java com.facebook.infrastructure.cli.CliMain ", options);
// System.exit(1);
}
else
{
css.hostName = cmd.getOptionValue(HOST_OPTION);
}
// Look for optional args.
if (cmd.hasOption(PORT_OPTION))
{
css.thriftPort = Integer.parseInt(cmd.getOptionValue(PORT_OPTION));
}
else
{
css.thriftPort = DEFAULT_THRIFT_PORT;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,42 @@
/**
* 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.cli;
import java.io.InputStream;
import java.io.PrintStream;
public class CliSessionState {
public boolean timingOn = false;
public String hostName; // cassandra server name
public int thriftPort; // cassandra server's thrift port
/*
* Streams to read/write from
*/
public InputStream in;
public PrintStream out;
public PrintStream err;
public CliSessionState() {
in = System.in;
out = System.out;
err = System.err;
}
}

View File

@ -0,0 +1,105 @@
lexer grammar Cli;
@header {
package com.facebook.infrastructure.cli;
}
T43 : '?' ;
T44 : '=' ;
T45 : '[' ;
T46 : ']' ;
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 166
K_CONFIG: 'CONFIG';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 167
K_CONNECT: 'CONNECT';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 168
K_CLUSTER: 'CLUSTER';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 169
K_DESCRIBE: 'DESCRIBE';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 170
K_GET: 'GET';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 171
K_HELP: 'HELP';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 172
K_EXIT: 'EXIT';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 173
K_FILE: 'FILE';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 174
K_NAME: 'NAME';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 175
K_QUIT: 'QUIT';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 176
K_SET: 'SET';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 177
K_SHOW: 'SHOW';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 178
K_TABLE: 'TABLE';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 179
K_TABLES: 'TABLES';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 180
K_THRIFT: 'THRIFT';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 181
K_VERSION: 'VERSION';
// private syntactic rules
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 184
fragment
Letter
: 'a'..'z'
| 'A'..'Z'
;
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 190
fragment
Digit
: '0'..'9'
;
// syntactic Elements
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 196
Identifier
: Letter ( Letter | Digit | '_')*
;
// literals
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 202
StringLiteral
:
'\'' (~'\'')* '\'' ( '\'' (~'\'')* '\'' )*
;
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 207
IntegerLiteral
: Digit+;
//
// syntactic elements
//
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 215
DOT
: '.'
;
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 219
SLASH
: '/'
;
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 223
SEMICOLON
: ';'
;
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 227
WS
: (' '|'\r'|'\t'|'\n') {$channel=HIDDEN;} // whitepace
;
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cli/Cli.g" 231
COMMENT
: '--' (~('\n'|'\r'))* { $channel=HIDDEN; }
| '/*' (options {greedy=false;} : .)* '*/' { $channel=HIDDEN; }
;

View File

@ -0,0 +1,319 @@
/**
* 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.concurrent;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class AIOExecutorService implements ExecutorService
{
private ExecutorService executorService_;
public AIOExecutorService(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory)
{
executorService_ = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
}
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the <tt>Executor</tt> implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution.
* @throws NullPointerException if command is null
*/
public void execute(Runnable command)
{
executorService_.execute(command);
}
/**
* Initiates an orderly shutdown in which previously submitted
* tasks are executed, but no new tasks will be accepted.
* Invocation has no additional effect if already shut down.
*
* <p>This method does not wait for previously submitted tasks to
* complete execution. Use {@link #awaitTermination awaitTermination}
* to do that.
*
* @throws SecurityException if a security manager exists and
* shutting down this ExecutorService may manipulate
* threads that the caller is not permitted to modify
* because it does not hold {@link
* java.lang.RuntimePermission}<tt>("modifyThread")</tt>,
* or the security manager's <tt>checkAccess</tt> method
* denies access.
*/
public void shutdown()
{
/* This is a noop. */
}
/**
* Attempts to stop all actively executing tasks, halts the
* processing of waiting tasks, and returns a list of the tasks
* that were awaiting execution.
*
* <p>This method does not wait for actively executing tasks to
* terminate. Use {@link #awaitTermination awaitTermination} to
* do that.
*
* <p>There are no guarantees beyond best-effort attempts to stop
* processing actively executing tasks. For example, typical
* implementations will cancel via {@link Thread#interrupt}, so any
* task that fails to respond to interrupts may never terminate.
*
* @return list of tasks that never commenced execution
* @throws SecurityException if a security manager exists and
* shutting down this ExecutorService may manipulate
* threads that the caller is not permitted to modify
* because it does not hold {@link
* java.lang.RuntimePermission}<tt>("modifyThread")</tt>,
* or the security manager's <tt>checkAccess</tt> method
* denies access.
*/
public List<Runnable> shutdownNow()
{
return executorService_.shutdownNow();
}
/**
* Returns <tt>true</tt> if this executor has been shut down.
*
* @return <tt>true</tt> if this executor has been shut down
*/
public boolean isShutdown()
{
return executorService_.isShutdown();
}
/**
* Returns <tt>true</tt> if all tasks have completed following shut down.
* Note that <tt>isTerminated</tt> is never <tt>true</tt> unless
* either <tt>shutdown</tt> or <tt>shutdownNow</tt> was called first.
*
* @return <tt>true</tt> if all tasks have completed following shut down
*/
public boolean isTerminated()
{
return executorService_.isTerminated();
}
/**
* Blocks until all tasks have completed execution after a shutdown
* request, or the timeout occurs, or the current thread is
* interrupted, whichever happens first.
*
* @param timeout the maximum time to wait
* @param unit the time unit of the timeout argument
* @return <tt>true</tt> if this executor terminated and
* <tt>false</tt> if the timeout elapsed before termination
* @throws InterruptedException if interrupted while waiting
*/
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException
{
return executorService_.awaitTermination(timeout, unit);
}
/**
* Submits a value-returning task for execution and returns a
* Future representing the pending results of the task. The
* Future's <tt>get</tt> method will return the task's result upon
* successful completion.
*
* <p>
* If you would like to immediately block waiting
* for a task, you can use constructions of the form
* <tt>result = exec.submit(aCallable).get();</tt>
*
* <p> Note: The {@link Executors} class includes a set of methods
* that can convert some other common closure-like objects,
* for example, {@link java.security.PrivilegedAction} to
* {@link Callable} form so they can be submitted.
*
* @param task the task to submit
* @return a Future representing pending completion of the task
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
* @throws NullPointerException if the task is null
*/
public <T> Future<T> submit(Callable<T> task)
{
return executorService_.submit(task);
}
/**
* Submits a Runnable task for execution and returns a Future
* representing that task. The Future's <tt>get</tt> method will
* return the given result upon successful completion.
*
* @param task the task to submit
* @param result the result to return
* @return a Future representing pending completion of the task
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
* @throws NullPointerException if the task is null
*/
public <T> Future<T> submit(Runnable task, T result)
{
return executorService_.submit(task, result);
}
/**
* Submits a Runnable task for execution and returns a Future
* representing that task. The Future's <tt>get</tt> method will
* return <tt>null</tt> upon <em>successful</em> completion.
*
* @param task the task to submit
* @return a Future representing pending completion of the task
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
* @throws NullPointerException if the task is null
*/
public Future<?> submit(Runnable task)
{
return executorService_.submit(task);
}
/**
* Executes the given tasks, returning a list of Futures holding
* their status and results when all complete.
* {@link Future#isDone} is <tt>true</tt> for each
* element of the returned list.
* Note that a <em>completed</em> task could have
* terminated either normally or by throwing an exception.
* The results of this method are undefined if the given
* collection is modified while this operation is in progress.
*
* @param tasks the collection of tasks
* @return A list of Futures representing the tasks, in the same
* sequential order as produced by the iterator for the
* given task list, each of which has completed.
* @throws InterruptedException if interrupted while waiting, in
* which case unfinished tasks are cancelled.
* @throws NullPointerException if tasks or any of its elements are <tt>null</tt>
* @throws RejectedExecutionException if any task cannot be
* scheduled for execution
*/
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException
{
return executorService_.invokeAll(tasks);
}
/**
* Executes the given tasks, returning a list of Futures holding
* their status and results
* when all complete or the timeout expires, whichever happens first.
* {@link Future#isDone} is <tt>true</tt> for each
* element of the returned list.
* Upon return, tasks that have not completed are cancelled.
* Note that a <em>completed</em> task could have
* terminated either normally or by throwing an exception.
* The results of this method are undefined if the given
* collection is modified while this operation is in progress.
*
* @param tasks the collection of tasks
* @param timeout the maximum time to wait
* @param unit the time unit of the timeout argument
* @return a list of Futures representing the tasks, in the same
* sequential order as produced by the iterator for the
* given task list. If the operation did not time out,
* each task will have completed. If it did time out, some
* of these tasks will not have completed.
* @throws InterruptedException if interrupted while waiting, in
* which case unfinished tasks are cancelled
* @throws NullPointerException if tasks, any of its elements, or
* unit are <tt>null</tt>
* @throws RejectedExecutionException if any task cannot be scheduled
* for execution
*/
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException
{
return executorService_.invokeAll(tasks, timeout, unit);
}
/**
* Executes the given tasks, returning the result
* of one that has completed successfully (i.e., without throwing
* an exception), if any do. Upon normal or exceptional return,
* tasks that have not completed are cancelled.
* The results of this method are undefined if the given
* collection is modified while this operation is in progress.
*
* @param tasks the collection of tasks
* @return the result returned by one of the tasks
* @throws InterruptedException if interrupted while waiting
* @throws NullPointerException if tasks or any of its elements
* are <tt>null</tt>
* @throws IllegalArgumentException if tasks is empty
* @throws ExecutionException if no task successfully completes
* @throws RejectedExecutionException if tasks cannot be scheduled
* for execution
*/
public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException
{
return executorService_.invokeAny(tasks);
}
/**
* Executes the given tasks, returning the result
* of one that has completed successfully (i.e., without throwing
* an exception), if any do before the given timeout elapses.
* Upon normal or exceptional return, tasks that have not
* completed are cancelled.
* The results of this method are undefined if the given
* collection is modified while this operation is in progress.
*
* @param tasks the collection of tasks
* @param timeout the maximum time to wait
* @param unit the time unit of the timeout argument
* @return the result returned by one of the tasks.
* @throws InterruptedException if interrupted while waiting
* @throws NullPointerException if tasks, any of its elements, or
* unit are <tt>null</tt>
* @throws TimeoutException if the given timeout elapses before
* any task successfully completes
* @throws ExecutionException if no task successfully completes
* @throws RejectedExecutionException if tasks cannot be scheduled
* for execution
*/
public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
{
return executorService_.invokeAny(tasks, timeout, unit);
}
}

View File

@ -0,0 +1,52 @@
/**
* 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.concurrent;
import java.util.HashMap;
import java.util.Map;
/**
* Context object adding a collection of key/value pairs into ThreadLocalContext.
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
*/
public class Context
{
private Map<Object, Object> ht_;
public Context()
{
ht_ = new HashMap<Object, Object>();
}
public Object put(Object key, Object value)
{
return ht_.put(key, value);
}
public Object get(Object key)
{
return ht_.get(key);
}
public void remove(Object key)
{
ht_.remove(key);
}
}

View File

@ -0,0 +1,53 @@
/**
* 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.concurrent;
import org.apache.cassandra.continuations.Suspendable;
import org.apache.commons.javaflow.Continuation;
public class ContinuationContext
{
private Continuation continuation_;
private Object result_;
public ContinuationContext(Continuation continuation)
{
continuation_ = continuation;
}
public Continuation getContinuation()
{
return continuation_;
}
public void setContinuation(Continuation continuation)
{
continuation_ = continuation;
}
public Object result()
{
return result_;
}
public void result(Object result)
{
result_ = result;
}
}

View File

@ -0,0 +1,91 @@
/**
* 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.concurrent;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.apache.cassandra.continuations.Suspendable;
public class ContinuationStage implements IStage
{
private String name_;
private ContinuationsExecutor executorService_;
public ContinuationStage(String name, int numThreads)
{
name_ = name;
executorService_ = new ContinuationsExecutor( numThreads,
numThreads,
Integer.MAX_VALUE,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(),
new ThreadFactoryImpl(name)
);
}
public String getName()
{
return name_;
}
public ExecutorService getInternalThreadPool()
{
return executorService_;
}
public Future<Object> execute(Callable<Object> callable) {
return executorService_.submit(callable);
}
public void execute(Runnable runnable) {
executorService_.execute(runnable);
}
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)
{
throw new UnsupportedOperationException("This operation is not supported");
}
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
throw new UnsupportedOperationException("This operation is not supported");
}
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
throw new UnsupportedOperationException("This operation is not supported");
}
public void shutdown() {
executorService_.shutdownNow();
}
public boolean isShutdown()
{
return executorService_.isShutdown();
}
public long getTaskCount(){
return (executorService_.getTaskCount() - executorService_.getCompletedTaskCount());
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,76 @@
/**
* 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.concurrent;
import java.util.concurrent.*;
import org.apache.cassandra.utils.LogUtil;
import org.apache.log4j.Logger;
import org.apache.cassandra.utils.*;
/**
* This is a wrapper class for the <i>ScheduledThreadPoolExecutor</i>. It provides an implementation
* for the <i>afterExecute()</i> found in the <i>ThreadPoolExecutor</i> class to log any unexpected
* Runtime Exceptions.
*
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
*/
public final class DebuggableScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor
{
private static Logger logger_ = Logger.getLogger(DebuggableScheduledThreadPoolExecutor.class);
public DebuggableScheduledThreadPoolExecutor(int threads,
ThreadFactory threadFactory)
{
super(threads, threadFactory);
}
/**
* (non-Javadoc)
* @see java.util.concurrent.ThreadPoolExecutor#afterExecute(java.lang.Runnable, java.lang.Throwable)
*/
public void afterExecute(Runnable r, Throwable t)
{
super.afterExecute(r,t);
if ( t != null )
{
Context ctx = ThreadLocalContext.get();
if ( ctx != null )
{
Object object = ctx.get(r.getClass().getName());
if ( object != null )
{
logger_.info("**** In afterExecute() " + t.getClass().getName() + " occured while working with " + object + " ****");
}
else
{
logger_.info("**** In afterExecute() " + t.getClass().getName() + " occured ****");
}
}
Throwable cause = t.getCause();
if ( cause != null )
{
logger_.info( LogUtil.throwableToString(cause) );
}
logger_.info( LogUtil.throwableToString(t) );
}
}
}

View File

@ -0,0 +1,85 @@
/**
* 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.concurrent;
import java.util.concurrent.*;
import org.apache.cassandra.utils.LogUtil;
import org.apache.log4j.Logger;
import org.apache.cassandra.utils.*;
/**
* This is a wrapper class for the <i>ScheduledThreadPoolExecutor</i>. It provides an implementation
* for the <i>afterExecute()</i> found in the <i>ThreadPoolExecutor</i> class to log any unexpected
* Runtime Exceptions.
*
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
*/
public final class DebuggableThreadPoolExecutor extends ThreadPoolExecutor
{
private static Logger logger_ = Logger.getLogger(DebuggableThreadPoolExecutor.class);
public DebuggableThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory)
{
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
super.prestartAllCoreThreads();
}
/*
*
* (non-Javadoc)
* @see java.util.concurrent.ThreadPoolExecutor#afterExecute(java.lang.Runnable, java.lang.Throwable)
* Helps us in figuring out why sometimes the threads are getting
* killed and replaced by new ones.
*/
public void afterExecute(Runnable r, Throwable t)
{
super.afterExecute(r,t);
if ( t != null )
{
Context ctx = ThreadLocalContext.get();
if ( ctx != null )
{
Object object = ctx.get(r.getClass().getName());
if ( object != null )
{
logger_.info("**** In afterExecute() " + t.getClass().getName() + " occured while working with " + object + " ****");
}
else
{
logger_.info("**** In afterExecute() " + t.getClass().getName() + " occured ****");
}
}
Throwable cause = t.getCause();
if ( cause != null )
{
logger_.info( LogUtil.throwableToString(cause) );
}
logger_.info( LogUtil.throwableToString(t) );
}
}
}

View File

@ -0,0 +1,26 @@
/**
* 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.concurrent;
import org.apache.commons.javaflow.Continuation;
public interface IContinuable
{
public void run(Continuation c);
}

View File

@ -0,0 +1,120 @@
/**
* 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.concurrent;
import java.util.concurrent.*;
/**
* An abstraction for stages as described in the SEDA paper by Matt Welsh.
* For reference to the paper look over here
* <a href="http://www.eecs.harvard.edu/~mdw/papers/seda-sosp01.pdf">SEDA: An Architecture for WellConditioned,
Scalable Internet Services</a>.
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
*/
public interface IStage
{
/**
* Get the name of the associated stage
* @return
*/
public String getName();
/**
* Get the thread pool used by this stage
* internally.
*/
public ExecutorService getInternalThreadPool();
/**
* This method is used to execute a peice of code on
* this stage. The idea is that the <i>run()</i> method
* of this Runnable instance is invoked on a thread from a
* thread pool that belongs to this stage.
* @param runnable instance whose run() method needs to be invoked.
*/
public void execute(Runnable runnable);
/**
* This method is used to execute a peice of code on
* this stage which returns a Future pointer. The idea
* is that the <i>call()</i> method of this Runnable
* instance is invoked on a thread from a thread pool
* that belongs to this stage.
* @param callable instance that needs to be invoked.
* @return
*/
public Future<Object> execute(Callable<Object> callable);
/**
* This method is used to submit tasks to this stage
* that execute periodically.
*
* @param command the task to execute.
* @param initialDelay the time to delay first execution
* @param unit the time unit of the initialDelay and period parameters
* @return
*/
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);
/**
* This method is used to submit tasks to this stage
* that execute periodically.
* @param command the task to execute.
* @param initialDelay the time to delay first execution
* @param period the period between successive executions
* @param unit the time unit of the initialDelay and period parameters
* @return
*/
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);
/**
* This method is used to submit tasks to this stage
* that execute periodically.
* @param command the task to execute.
* @param initialDelay the time to delay first execution
* @param delay the delay between the termination of one execution and the commencement of the next.
* @param unit the time unit of the initialDelay and delay parameters
* @return
*/
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit);
/**
* Shutdown the stage. All the threads of this stage
* are forcefully shutdown. Any pending tasks on this
* stage could be dropped or the stage could wait for
* these tasks to be completed. This is however an
* implementation detail.
*/
public void shutdown();
/**
* Checks if the stage has been shutdown.
* @return
*/
public boolean isShutdown();
/**
* This method returns the number of tasks that are
* pending on this stage to be executed.
* @return
*/
public long getTaskCount();
}

View File

@ -0,0 +1,98 @@
/**
* 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.concurrent;
import java.util.concurrent.*;
import javax.naming.OperationNotSupportedException;
import org.apache.cassandra.net.EndPoint;
import org.apache.cassandra.net.MessagingService;
import org.apache.cassandra.utils.LogUtil;
import org.apache.log4j.Logger;
/**
* This class is an implementation of the <i>IStage</i> interface. In particular
* it is for a stage that has a thread pool with multiple threads. For details
* please refer to the <i>IStage</i> documentation.
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
*/
public class MultiThreadedStage implements IStage
{
private String name_;
private DebuggableThreadPoolExecutor executorService_;
public MultiThreadedStage(String name, int numThreads)
{
name_ = name;
executorService_ = new DebuggableThreadPoolExecutor( numThreads,
numThreads,
Integer.MAX_VALUE,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(),
new ThreadFactoryImpl(name)
);
}
public String getName()
{
return name_;
}
public ExecutorService getInternalThreadPool()
{
return executorService_;
}
public Future<Object> execute(Callable<Object> callable) {
return executorService_.submit(callable);
}
public void execute(Runnable runnable) {
executorService_.execute(runnable);
}
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)
{
throw new UnsupportedOperationException("This operation is not supported");
}
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
throw new UnsupportedOperationException("This operation is not supported");
}
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
throw new UnsupportedOperationException("This operation is not supported");
}
public void shutdown() {
executorService_.shutdownNow();
}
public boolean isShutdown()
{
return executorService_.isShutdown();
}
public long getTaskCount(){
return (executorService_.getTaskCount() - executorService_.getCompletedTaskCount());
}
}

View File

@ -0,0 +1,24 @@
/**
* 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.concurrent;
interface RejectedExecutionHandler
{
public void rejectedExecution(Runnable r, ContinuationsExecutor executor);
}

View File

@ -0,0 +1,100 @@
/**
* 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.concurrent;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class SingleThreadedContinuationStage implements IStage
{
protected ContinuationsExecutor executorService_;
private String name_;
public SingleThreadedContinuationStage(String name)
{
executorService_ = new ContinuationsExecutor( 1,
1,
Integer.MAX_VALUE,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(),
new ThreadFactoryImpl(name)
);
name_ = name;
}
/* Implementing the IStage interface methods */
public String getName()
{
return name_;
}
public ExecutorService getInternalThreadPool()
{
return executorService_;
}
public void execute(Runnable runnable)
{
executorService_.execute(runnable);
}
public Future<Object> execute(Callable<Object> callable)
{
return executorService_.submit(callable);
}
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)
{
//return executorService_.schedule(command, delay, unit);
throw new UnsupportedOperationException("This operation is not supported");
}
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
{
//return executorService_.scheduleAtFixedRate(command, initialDelay, period, unit);
throw new UnsupportedOperationException("This operation is not supported");
}
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
{
//return executorService_.scheduleWithFixedDelay(command, initialDelay, delay, unit);
throw new UnsupportedOperationException("This operation is not supported");
}
public void shutdown()
{
executorService_.shutdownNow();
}
public boolean isShutdown()
{
return executorService_.isShutdown();
}
public long getTaskCount(){
return (executorService_.getTaskCount() - executorService_.getCompletedTaskCount());
}
/* Finished implementing the IStage interface methods */
}

View File

@ -0,0 +1,108 @@
/**
* 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.concurrent;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.apache.cassandra.net.*;
/**
* This class is an implementation of the <i>IStage</i> interface. In particular
* it is for a stage that has a thread pool with a single thread. For details
* please refer to the <i>IStage</i> documentation.
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
*/
public class SingleThreadedStage implements IStage
{
protected DebuggableThreadPoolExecutor executorService_;
private String name_;
public SingleThreadedStage(String name)
{
//executorService_ = new DebuggableScheduledThreadPoolExecutor(1,new ThreadFactoryImpl(name));
executorService_ = new DebuggableThreadPoolExecutor( 1,
1,
Integer.MAX_VALUE,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(),
new ThreadFactoryImpl(name)
);
name_ = name;
}
/* Implementing the IStage interface methods */
public String getName()
{
return name_;
}
public ExecutorService getInternalThreadPool()
{
return executorService_;
}
public void execute(Runnable runnable)
{
executorService_.execute(runnable);
}
public Future<Object> execute(Callable<Object> callable)
{
return executorService_.submit(callable);
}
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)
{
//return executorService_.schedule(command, delay, unit);
throw new UnsupportedOperationException("This operation is not supported");
}
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
{
//return executorService_.scheduleAtFixedRate(command, initialDelay, period, unit);
throw new UnsupportedOperationException("This operation is not supported");
}
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
{
//return executorService_.scheduleWithFixedDelay(command, initialDelay, delay, unit);
throw new UnsupportedOperationException("This operation is not supported");
}
public void shutdown()
{
executorService_.shutdownNow();
}
public boolean isShutdown()
{
return executorService_.isShutdown();
}
public long getTaskCount(){
return (executorService_.getTaskCount() - executorService_.getCompletedTaskCount());
}
/* Finished implementing the IStage interface methods */
}

View File

@ -0,0 +1,119 @@
/**
* 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.concurrent;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import org.apache.cassandra.continuations.Suspendable;
/**
* This class manages all stages that exist within a process. The application registers
* and de-registers stages with this abstraction. Any component that has the <i>ID</i>
* associated with a stage can obtain a handle to actual stage.
*
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
*/
public class StageManager
{
private static Map<String, IStage > stageQueues_ = new HashMap<String, IStage>();
/**
* Register a stage with the StageManager
* @param stageName stage name.
* @param stage stage for the respective message types.
*/
public static void registerStage(String stageName, IStage stage)
{
stageQueues_.put(stageName, stage);
}
/**
* Returns the stage that we are currently executing on.
* This relies on the fact that the thread names in the
* stage have the name of the stage as the prefix.
* @return
*/
public static IStage getCurrentStage()
{
String name = Thread.currentThread().getName();
String[] peices = name.split(":");
IStage stage = getStage(peices[0]);
return stage;
}
/**
* Retrieve a stage from the StageManager
* @param stageName name of the stage to be retrieved.
*/
public static IStage getStage(String stageName)
{
return stageQueues_.get(stageName);
}
/**
* Retrieve the internal thread pool associated with the
* specified stage name.
* @param stageName name of the stage.
*/
public static ExecutorService getStageInternalThreadPool(String stageName)
{
IStage stage = getStage(stageName);
if ( stage == null )
throw new IllegalArgumentException("No stage registered with name " + stageName);
return stage.getInternalThreadPool();
}
/**
* Deregister a stage from StageManager
* @param stageName stage name.
*/
public static void deregisterStage(String stageName)
{
stageQueues_.remove(stageName);
}
/**
* This method gets the number of tasks on the
* stage's internal queue.
* @param stage name of the stage
* @return
*/
public static long getStageTaskCount(String stage)
{
return stageQueues_.get(stage).getTaskCount();
}
/**
* This method shuts down all registered stages.
*/
public static void shutdown()
{
Set<String> stages = stageQueues_.keySet();
for ( String stage : stages )
{
IStage registeredStage = stageQueues_.get(stage);
registeredStage.shutdown();
}
}
}

View File

@ -0,0 +1,51 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.concurrent;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import org.apache.cassandra.utils.*;
/**
* This class is an implementation of the <i>ThreadFactory</i> interface. This
* is useful to give Java threads meaningful names which is useful when using
* a tool like JConsole.
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
*/
public class ThreadFactoryImpl implements ThreadFactory
{
protected String id_;
protected ThreadGroup threadGroup_;
protected final AtomicInteger threadNbr_ = new AtomicInteger(1);
public ThreadFactoryImpl(String id)
{
SecurityManager sm = System.getSecurityManager();
threadGroup_ = ( sm != null ) ? sm.getThreadGroup() : Thread.currentThread().getThreadGroup();
id_ = id;
}
public Thread newThread(Runnable runnable)
{
String name = id_ + ":" + threadNbr_.getAndIncrement();
Thread thread = new Thread(threadGroup_, runnable, name);
return thread;
}
}

View File

@ -0,0 +1,42 @@
/**
* 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.concurrent;
/**
* Use this implementation over Java's ThreadLocal or InheritableThreadLocal when
* you need to add multiple key/value pairs into ThreadLocalContext for a given thread.
*
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
*/
public class ThreadLocalContext
{
private static InheritableThreadLocal<Context> tls_ = new InheritableThreadLocal<Context>();
public static void put(Context value)
{
tls_.set(value);
}
public static Context get()
{
return tls_.get();
}
}

View File

@ -0,0 +1,54 @@
/**
* 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.config;
public class CFMetaData
{
public String tableName; // name of table which has this column family
public String cfName; // name of the column family
public String columnType; // type: super, standard, etc.
public String indexProperty_; // name sorted, time stamp sorted etc.
// The user chosen names (n_) for various parts of data in a column family.
// CQL queries, for instance, will refer to/extract data within a column
// family using these logical names.
public String n_rowKey;
public String n_superColumnMap; // only used if this is a super column family
public String n_superColumnKey; // only used if this is a super column family
public String n_columnMap;
public String n_columnKey;
public String n_columnValue;
public String n_columnTimestamp;
// a quick and dirty pretty printer for describing the column family...
public String pretty()
{
String desc;
desc = n_columnMap + "(" + n_columnKey + ", " + n_columnValue + ", " + n_columnTimestamp + ")";
if ("Super".equals(columnType))
{
desc = n_superColumnMap + "(" + n_superColumnKey + ", " + desc + ")";
}
desc = tableName + "." + cfName + "(" + n_rowKey + ", " + desc + ")\n";
desc += "Column Family Type: " + columnType + "\n" +
"Columns Sorted By: " + indexProperty_ + "\n";
return desc;
}
}

View File

@ -0,0 +1,743 @@
/**
* 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.config;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.io.*;
import org.apache.cassandra.db.ColumnFamily;
import org.apache.cassandra.db.Table;
import org.apache.cassandra.db.TypeInfo;
import org.apache.cassandra.db.Table.TableMetadata;
import org.apache.cassandra.utils.FileUtils;
import org.apache.cassandra.utils.XMLUtils;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.apache.cassandra.io.*;
/**
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
*/
public class DatabaseDescriptor
{
public static final String random_ = "RANDOM";
public static final String ophf_ = "OPHF";
private static int storagePort_ = 7000;
private static int controlPort_ = 7001;
private static int httpPort_ = 7002;
private static String clusterName_ = "Test";
private static int replicationFactor_ = 3;
private static long rpcTimeoutInMillis_ = 2000;
private static Set<String> seeds_ = new HashSet<String>();
private static String metadataDirectory_;
private static String snapshotDirectory_;
/* Keeps the list of Ganglia servers to contact */
private static String[] gangliaServers_ ;
/* Keeps the list of map output directories */
private static String[] mapOutputDirectories_;
/* Keeps the list of data file directories */
private static String[] dataFileDirectories_;
/* Current index into the above list of directories */
private static int currentIndex_ = 0;
private static String logFileDirectory_;
private static String bootstrapFileDirectory_;
private static int logRotationThreshold_ = 128*1024*1024;
private static boolean fastSync_ = false;
private static boolean rackAware_ = false;
private static int threadsPerPool_ = 4;
private static List<String> tables_ = new ArrayList<String>();
private static Set<String> applicationColumnFamilies_ = new HashSet<String>();
// Default descriptive names for use in CQL. The user can override
// these choices in the config file. These are not case sensitive.
// Hence, these are stored in UPPER case for easy comparison.
private static String d_rowKey_ = "ROW_KEY";
private static String d_superColumnMap_ = "SUPER_COLUMN_MAP";
private static String d_superColumnKey_ = "SUPER_COLUMN_KEY";
private static String d_columnMap_ = "COLUMN_MAP";
private static String d_columnKey_ = "COLUMN_KEY";
private static String d_columnValue_ = "COLUMN_VALUE";
private static String d_columnTimestamp_ = "COLUMN_TIMESTAMP";
/*
* A map from table names to the set of column families for the table and the
* corresponding meta data for that column family.
*/
private static Map<String, Map<String, CFMetaData>> tableToCFMetaDataMap_;
/* Hashing strategy Random or OPHF */
private static String hashingStrategy_ = DatabaseDescriptor.random_;
/* if the size of columns or super-columns are more than this, indexing will kick in */
private static int columnIndexSizeInKB_;
/* Size of touch key cache */
private static int touchKeyCacheSize_ = 1024;
/* Number of hours to keep a memtable in memory */
private static int memtableLifetime_ = 6;
/* Size of the memtable in memory before it is dumped */
private static int memtableSize_ = 128;
/* Number of objects in millions in the memtable before it is dumped */
private static int memtableObjectCount_ = 1;
/*
* This parameter enables or disables consistency checks.
* If set to false the read repairs are disable for very
* high throughput on reads but at the cost of consistency.
*/
private static boolean doConsistencyCheck_ = true;
/* Address of ZooKeeper cell */
private static String zkAddress_;
/* Callout directories */
private static String calloutLocation_;
/* Job Jar Location */
private static String jobJarFileLocation_;
/* Address where to run the job tracker */
private static String jobTrackerHost_;
/* Zookeeper session timeout. */
private static int zkSessionTimeout_ = 30000;
// the path qualified config file (storage-conf.xml) name
private static String configFileName_;
public static Map<String, Map<String, CFMetaData>> init(String filePath) throws Throwable
{
/* Read the configuration file to retrieve DB related properties. */
String file = filePath + System.getProperty("file.separator") + "storage-conf.xml";
return initInternal(file);
}
public static Map<String, Map<String, CFMetaData>> init() throws Throwable
{
/* Read the configuration file to retrieve DB related properties. */
configFileName_ = System.getProperty("storage-config") + System.getProperty("file.separator") + "storage-conf.xml";
return initInternal(configFileName_);
}
public static Map<String, Map<String, CFMetaData>> initInternal(String file) throws Throwable
{
String os = System.getProperty("os.name");
XMLUtils xmlUtils = new XMLUtils(file);
/* Cluster Name */
clusterName_ = xmlUtils.getNodeValue("/Storage/ClusterName");
/* Ganglia servers contact list */
gangliaServers_ = xmlUtils.getNodeValues("/Storage/GangliaServers/GangliaServer");
/* ZooKeeper's address */
zkAddress_ = xmlUtils.getNodeValue("/Storage/ZookeeperAddress");
/* Hashing strategy */
hashingStrategy_ = xmlUtils.getNodeValue("/Storage/HashingStrategy");
/* Callout location */
calloutLocation_ = xmlUtils.getNodeValue("/Storage/CalloutLocation");
/* JobTracker address */
jobTrackerHost_ = xmlUtils.getNodeValue("/Storage/JobTrackerHost");
/* Job Jar file location */
jobJarFileLocation_ = xmlUtils.getNodeValue("/Storage/JobJarFileLocation");
/* Zookeeper's session timeout */
String zkSessionTimeout = xmlUtils.getNodeValue("/Storage/ZookeeperSessionTimeout");
if ( zkSessionTimeout != null )
zkSessionTimeout_ = Integer.parseInt(zkSessionTimeout);
/* Data replication factor */
String replicationFactor = xmlUtils.getNodeValue("/Storage/ReplicationFactor");
if ( replicationFactor != null )
replicationFactor_ = Integer.parseInt(replicationFactor);
/* RPC Timeout */
String rpcTimeoutInMillis = xmlUtils.getNodeValue("/Storage/RpcTimeoutInMillis");
if ( rpcTimeoutInMillis != null )
rpcTimeoutInMillis_ = Integer.parseInt(rpcTimeoutInMillis);
/* Thread per pool */
String threadsPerPool = xmlUtils.getNodeValue("/Storage/ThreadsPerPool");
if ( threadsPerPool != null )
threadsPerPool_ = Integer.parseInt(threadsPerPool);
/* TCP port on which the storage system listens */
String port = xmlUtils.getNodeValue("/Storage/StoragePort");
if ( port != null )
storagePort_ = Integer.parseInt(port);
/* UDP port for control messages */
port = xmlUtils.getNodeValue("/Storage/ControlPort");
if ( port != null )
controlPort_ = Integer.parseInt(port);
/* HTTP port for HTTP messages */
port = xmlUtils.getNodeValue("/Storage/HttpPort");
if ( port != null )
httpPort_ = Integer.parseInt(port);
/* Touch Key Cache Size */
String touchKeyCacheSize = xmlUtils.getNodeValue("/Storage/TouchKeyCacheSize");
if ( touchKeyCacheSize != null )
touchKeyCacheSize_ = Integer.parseInt(touchKeyCacheSize);
/* Number of days to keep the memtable around w/o flushing */
String lifetime = xmlUtils.getNodeValue("/Storage/MemtableLifetimeInDays");
if ( lifetime != null )
memtableLifetime_ = Integer.parseInt(lifetime);
/* Size of the memtable in memory in MB before it is dumped */
String memtableSize = xmlUtils.getNodeValue("/Storage/MemtableSizeInMB");
if ( memtableSize != null )
memtableSize_ = Integer.parseInt(memtableSize);
/* Number of objects in millions in the memtable before it is dumped */
String memtableObjectCount = xmlUtils.getNodeValue("/Storage/MemtableObjectCountInMillions");
if ( memtableObjectCount != null )
memtableObjectCount_ = Integer.parseInt(memtableObjectCount);
/* This parameter enables or disables consistency checks.
* If set to false the read repairs are disable for very
* high throughput on reads but at the cost of consistency.*/
String doConsistencyCheck = xmlUtils.getNodeValue("/Storage/DoConsistencyChecksBoolean");
if ( doConsistencyCheck != null )
doConsistencyCheck_ = Boolean.parseBoolean(doConsistencyCheck);
/* read the size at which we should do column indexes */
String columnIndexSizeInKB = xmlUtils.getNodeValue("/Storage/ColumnIndexSizeInKB");
if(columnIndexSizeInKB == null)
{
columnIndexSizeInKB_ = 64;
}
else
{
columnIndexSizeInKB_ = Integer.parseInt(columnIndexSizeInKB);
}
/* metadata directory */
metadataDirectory_ = xmlUtils.getNodeValue("/Storage/MetadataDirectory");
if ( metadataDirectory_ != null )
FileUtils.createDirectory(metadataDirectory_);
else
{
if ( os.equals("Linux") )
{
metadataDirectory_ = "/var/storage/system";
}
}
/* snapshot directory */
snapshotDirectory_ = xmlUtils.getNodeValue("/Storage/SnapshotDirectory");
if ( snapshotDirectory_ != null )
FileUtils.createDirectory(snapshotDirectory_);
else
{
snapshotDirectory_ = metadataDirectory_ + System.getProperty("file.separator") + "snapshot";
}
/* map output directory */
mapOutputDirectories_ = xmlUtils.getNodeValues("/Storage/MapOutputDirectories/MapOutputDirectory");
if ( mapOutputDirectories_.length > 0 )
{
for ( String mapOutputDirectory : mapOutputDirectories_ )
FileUtils.createDirectory(mapOutputDirectory);
}
/* data file directory */
dataFileDirectories_ = xmlUtils.getNodeValues("/Storage/DataFileDirectories/DataFileDirectory");
if ( dataFileDirectories_.length > 0 )
{
for ( String dataFileDirectory : dataFileDirectories_ )
FileUtils.createDirectory(dataFileDirectory);
}
else
{
if ( os.equals("Linux") )
{
dataFileDirectories_ = new String[]{"/var/storage/data"};
}
}
/* bootstrap file directory */
bootstrapFileDirectory_ = xmlUtils.getNodeValue("/Storage/BootstrapFileDirectory");
if ( bootstrapFileDirectory_ != null )
FileUtils.createDirectory(bootstrapFileDirectory_);
else
{
if ( os.equals("Linux") )
{
bootstrapFileDirectory_ = "/var/storage/bootstrap";
}
}
/* commit log directory */
logFileDirectory_ = xmlUtils.getNodeValue("/Storage/CommitLogDirectory");
if ( logFileDirectory_ != null )
FileUtils.createDirectory(logFileDirectory_);
else
{
if ( os.equals("Linux") )
{
logFileDirectory_ = "/var/storage/commitlog";
}
}
/* threshold after which commit log should be rotated. */
String value = xmlUtils.getNodeValue("/Storage/CommitLogRotationThresholdInMB");
if ( value != null)
logRotationThreshold_ = Integer.parseInt(value) * 1024 * 1024;
/* fast sync option */
value = xmlUtils.getNodeValue("/Storage/CommitLogFastSync");
if ( value != null )
fastSync_ = Boolean.parseBoolean(value);
tableToCFMetaDataMap_ = new HashMap<String, Map<String, CFMetaData>>();
/* Rack Aware option */
value = xmlUtils.getNodeValue("/Storage/RackAware");
if ( value != null )
rackAware_ = Boolean.parseBoolean(value);
/* Read the table related stuff from config */
NodeList tables = xmlUtils.getRequestedNodeList("/Storage/Tables/Table");
int size = tables.getLength();
for ( int i = 0; i < size; ++i )
{
Node table = tables.item(i);
/* parsing out the table name */
String tName = XMLUtils.getAttributeValue(table, "Name");
tables_.add(tName);
tableToCFMetaDataMap_.put(tName, new HashMap<String, CFMetaData>());
String xqlTable = "/Storage/Tables/Table[@Name='" + tName + "']/";
NodeList columnFamilies = xmlUtils.getRequestedNodeList(xqlTable + "ColumnFamily");
// get name of the rowKey for this table
String n_rowKey = xmlUtils.getNodeValue(xqlTable + "RowKey");
if (n_rowKey == null)
n_rowKey = d_rowKey_;
//NodeList columnFamilies = xmlUtils.getRequestedNodeList(table, "ColumnFamily");
int size2 = columnFamilies.getLength();
for ( int j = 0; j < size2; ++j )
{
Node columnFamily = columnFamilies.item(j);
String cName = XMLUtils.getAttributeValue(columnFamily, "Name");
String xqlCF = xqlTable + "ColumnFamily[@Name='" + cName + "']/";
/* squirrel away the application column families */
applicationColumnFamilies_.add(cName);
// Parse out the column type
String columnType = xmlUtils.getAttributeValue(columnFamily, "ColumnType");
columnType = ColumnFamily.getColumnType(columnType);
// Parse out the column family sorting property for columns
String columnIndexProperty = XMLUtils.getAttributeValue(columnFamily, "ColumnSort");
String columnIndexType = ColumnFamily.getColumnSortProperty(columnIndexProperty);
// Parse out user-specified logical names for the various dimensions
// of a the column family from the config.
String n_superColumnMap = xmlUtils.getNodeValue(xqlCF + "SuperColumnMap");
if (n_superColumnMap == null)
n_superColumnMap = d_superColumnMap_;
String n_superColumnKey = xmlUtils.getNodeValue(xqlCF + "SuperColumnKey");
if (n_superColumnKey == null)
n_superColumnKey = d_superColumnKey_;
String n_columnMap = xmlUtils.getNodeValue(xqlCF + "ColumnMap");
if (n_columnMap == null)
n_columnMap = d_columnMap_;
String n_columnKey = xmlUtils.getNodeValue(xqlCF + "ColumnKey");
if (n_columnKey == null)
n_columnKey = d_columnKey_;
String n_columnValue = xmlUtils.getNodeValue(xqlCF + "ColumnValue");
if (n_columnValue == null)
n_columnValue = d_columnValue_;
String n_columnTimestamp = xmlUtils.getNodeValue(xqlCF + "ColumnTimestamp");
if (n_columnTimestamp == null)
n_columnTimestamp = d_columnTimestamp_;
// now populate the column family meta data and
// insert it into the table dictionary.
CFMetaData cfMetaData = new CFMetaData();
cfMetaData.tableName = tName;
cfMetaData.cfName = cName;
cfMetaData.columnType = columnType;
cfMetaData.indexProperty_ = columnIndexType;
cfMetaData.n_rowKey = n_rowKey;
cfMetaData.n_columnMap = n_columnMap;
cfMetaData.n_columnKey = n_columnKey;
cfMetaData.n_columnValue = n_columnValue;
cfMetaData.n_columnTimestamp = n_columnTimestamp;
if ("Super".equals(columnType))
{
cfMetaData.n_superColumnKey = n_superColumnKey;
cfMetaData.n_superColumnMap = n_superColumnMap;
}
tableToCFMetaDataMap_.get(tName).put(cName, cfMetaData);
}
}
/* Load the seeds for node contact points */
String[] seeds = xmlUtils.getNodeValues("/Storage/Seeds/Seed");
for( int i = 0; i < seeds.length; ++i )
{
seeds_.add( seeds[i] );
}
return tableToCFMetaDataMap_;
}
public static String getHashingStrategy()
{
return hashingStrategy_;
}
public static String getZkAddress()
{
return zkAddress_;
}
public static String getCalloutLocation()
{
return calloutLocation_;
}
public static String getJobTrackerAddress()
{
return jobTrackerHost_;
}
public static int getZkSessionTimeout()
{
return zkSessionTimeout_;
}
public static int getColumnIndexSize()
{
return columnIndexSizeInKB_ * 1024;
}
public static int getMemtableLifetime()
{
return memtableLifetime_;
}
public static int getMemtableSize()
{
return memtableSize_;
}
public static int getMemtableObjectCount()
{
return memtableObjectCount_;
}
public static boolean getConsistencyCheck()
{
return doConsistencyCheck_;
}
public static String getClusterName()
{
return clusterName_;
}
public static String getConfigFileName() {
return configFileName_;
}
public static boolean isApplicationColumnFamily(String columnFamily)
{
return applicationColumnFamilies_.contains(columnFamily);
}
public static int getTouchKeyCacheSize()
{
return touchKeyCacheSize_;
}
public static String getJobJarLocation()
{
return jobJarFileLocation_;
}
public static String getGangliaServers()
{
StringBuilder sb = new StringBuilder();
for ( int i = 0; i < gangliaServers_.length; ++i )
{
sb.append(gangliaServers_[i]);
if ( i != (gangliaServers_.length - 1) )
sb.append(", ");
}
return sb.toString();
}
public static Map<String, CFMetaData> getTableMetaData(String table)
{
return tableToCFMetaDataMap_.get(table);
}
/*
* Given a table name & column family name, get the column family
* meta data. If the table name or column family name is not valid
* this function returns null.
*/
public static CFMetaData getCFMetaData(String table, String cfName)
{
Map<String, CFMetaData> cfInfo = tableToCFMetaDataMap_.get(table);
if (cfInfo == null)
return null;
return cfInfo.get(cfName);
}
public static String getColumnType(String cfName)
{
String table = getTables().get(0);
CFMetaData cfMetaData = getCFMetaData(table, cfName);
if (cfMetaData == null)
return null;
return cfMetaData.columnType;
}
public static boolean isNameSortingEnabled(String cfName)
{
String table = getTables().get(0);
CFMetaData cfMetaData = getCFMetaData(table, cfName);
if (cfMetaData == null)
return false;
return "Name".equals(cfMetaData.indexProperty_);
}
public static boolean isTimeSortingEnabled(String cfName)
{
String table = getTables().get(0);
CFMetaData cfMetaData = getCFMetaData(table, cfName);
if (cfMetaData == null)
return false;
return "Time".equals(cfMetaData.indexProperty_);
}
public static List<String> getTables()
{
return tables_;
}
public static void setTables(String table)
{
tables_.add(table);
}
public static int getStoragePort()
{
return storagePort_;
}
public static int getControlPort()
{
return controlPort_;
}
public static int getHttpPort()
{
return httpPort_;
}
public static int getReplicationFactor()
{
return replicationFactor_;
}
public static long getRpcTimeout()
{
return rpcTimeoutInMillis_;
}
public static int getThreadsPerPool()
{
return threadsPerPool_;
}
public static String getMetadataDirectory()
{
return metadataDirectory_;
}
public static void setMetadataDirectory(String metadataDirectory)
{
metadataDirectory_ = metadataDirectory;
}
public static String getSnapshotDirectory()
{
return snapshotDirectory_;
}
public static void setSnapshotDirectory(String snapshotDirectory)
{
snapshotDirectory_ = snapshotDirectory;
}
public static String[] getAllMapOutputDirectories()
{
return mapOutputDirectories_;
}
public static String getMapOutputLocation()
{
String mapOutputDirectory = mapOutputDirectories_[currentIndex_];
return mapOutputDirectory;
}
public static String[] getAllDataFileLocations()
{
return dataFileDirectories_;
}
public static String getDataFileLocation()
{
String dataFileDirectory = dataFileDirectories_[currentIndex_];
return dataFileDirectory;
}
public static String getCompactionFileLocation()
{
String dataFileDirectory = dataFileDirectories_[currentIndex_];
currentIndex_ = (currentIndex_ + 1 )%dataFileDirectories_.length ;
return dataFileDirectory;
}
public static String getBootstrapFileLocation()
{
return bootstrapFileDirectory_;
}
public static void setBootstrapFileLocation(String bfLocation)
{
bootstrapFileDirectory_ = bfLocation;
}
public static int getLogFileSizeThreshold()
{
return logRotationThreshold_;
}
public static String getLogFileLocation()
{
return logFileDirectory_;
}
public static void setLogFileLocation(String logLocation)
{
logFileDirectory_ = logLocation;
}
public static boolean isFastSync()
{
return fastSync_;
}
public static boolean isRackAware()
{
return rackAware_;
}
public static Set<String> getSeeds()
{
return seeds_;
}
public static String getColumnFamilyType(String cfName)
{
String cfType = getColumnType(cfName);
if ( cfType == null )
cfType = "Standard";
return cfType;
}
/*
* Loop through all the disks to see which disk has the max free space
* return the disk with max free space for compactions. If the size of the expected
* compacted file is greater than the max disk space available return null, we cannot
* do compaction in this case.
*/
public static String getCompactionFileLocation(long expectedCompactedFileSize)
{
long maxFreeDisk = 0;
int maxDiskIndex = 0;
String dataFileDirectory = null;
for ( int i = 0 ; i < dataFileDirectories_.length ; i++ )
{
File f = new File(dataFileDirectories_[i]);
if( maxFreeDisk < f.getUsableSpace())
{
maxFreeDisk = f.getUsableSpace();
maxDiskIndex = i;
}
}
// Load factor of 0.9 we do not want to use the entire disk that is too risky.
maxFreeDisk = (long)(0.9 * maxFreeDisk);
if( expectedCompactedFileSize < maxFreeDisk )
{
dataFileDirectory = dataFileDirectories_[maxDiskIndex];
currentIndex_ = (maxDiskIndex + 1 )%dataFileDirectories_.length ;
}
else
{
currentIndex_ = maxDiskIndex;
}
return dataFileDirectory;
}
public static TypeInfo getTypeInfo(String cfName)
{
String table = DatabaseDescriptor.getTables().get(0);
CFMetaData cfMetadata = DatabaseDescriptor.getCFMetaData(table, cfName);
if ( cfMetadata.indexProperty_.equals("Name") )
{
return TypeInfo.STRING;
}
else
{
return TypeInfo.LONG;
}
}
public static void main(String[] args) throws Throwable
{
DatabaseDescriptor.initInternal("C:\\Engagements\\Cassandra-Golden\\storage-conf.xml");
}
}

View File

@ -0,0 +1,36 @@
/**
* 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.continuations;
import java.lang.instrument.Instrumentation;
import org.apache.commons.javaflow.bytecode.transformation.bcel.BcelClassTransformer;
/**
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
*/
public class CAgent
{
public static void premain(String agentArguments, Instrumentation instrumentation)
{
instrumentation.addTransformer(new ContinuationClassTransformer(agentArguments, new BcelClassTransformer()));
}
}

View File

@ -0,0 +1,74 @@
/**
* 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.continuations;
import java.lang.annotation.Annotation;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.List;
import java.util.Set;
import java.util.HashSet;
import java.util.StringTokenizer;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import org.apache.commons.javaflow.bytecode.transformation.ResourceTransformer;
import org.apache.commons.javaflow.bytecode.transformation.bcel.BcelClassTransformer;
/**
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
*/
class ContinuationClassTransformer implements ClassFileTransformer
{
private static final String targetAnnotation_ = "Suspendable";
private ResourceTransformer transformer_;
public ContinuationClassTransformer(String agentArguments, ResourceTransformer transformer)
{
super();
transformer_ = transformer;
}
public byte[] transform(ClassLoader classLoader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) throws IllegalClassFormatException
{
/*
* Use the ASM class reader to see which classes support
* the Suspendable annotation. If they do then those
* classes need to have their bytecodes transformed for
* Continuation support.
*/
ClassReader classReader = new ClassReader(bytes);
ClassNode classNode = new ClassNode();
classReader.accept(classNode, true);
List<AnnotationNode> annotationNodes = classNode.visibleAnnotations;
for( AnnotationNode annotationNode : annotationNodes )
{
if ( annotationNode.desc.indexOf(ContinuationClassTransformer.targetAnnotation_) != -1 )
{
bytes = transformer_.transform(bytes);
}
}
return bytes;
}
}

View File

@ -0,0 +1,33 @@
/**
* 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.continuations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
/**
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
*/
public @interface Suspendable
{
}

View File

@ -0,0 +1,51 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.cql.common;
import org.apache.cassandra.cql.execution.RuntimeErrorMsg;
/**
* BindOperand:
* Represents a bind variable in the CQL statement. Lives
* in the shared execution plan.
*/
public class BindOperand implements OperandDef
{
int bindIndex_; // bind position
public BindOperand(int bindIndex)
{
bindIndex_ = bindIndex;
}
public Object get()
{
// TODO: Once bind variables are supported, the get() will extract
// the value of the bind at position "bindIndex_" from the execution
// context.
throw new RuntimeException(RuntimeErrorMsg.IMPLEMENTATION_RESTRICTION
.getMsg("bind params not yet supported"));
}
public String explain()
{
return "Bind #: " + bindIndex_;
}
};

View File

@ -0,0 +1,30 @@
/**
* 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.cql.common;
//Note: This class is CQL related work in progress.
public class CExpr
{
public static interface Expr
{
CType getType();
String toString();
};
}

View File

@ -0,0 +1,77 @@
/**
* 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.cql.common;
import java.util.ArrayList;
//Note: This class is CQL related work in progress.
public class CType
{
public static interface Type
{
String toString();
};
public static class IntegerType implements Type
{
public String toString() { return "Integer"; };
}
public static class StringType implements Type
{
public String toString() { return "String"; };
}
public static class RowType implements Type
{
ArrayList<Type> types_;
public RowType(ArrayList<Type> types)
{
types_ = types;
}
public String toString()
{
StringBuffer sb = new StringBuffer("<");
for (int idx = types_.size(); idx > 0; idx--)
{
sb.append(types_.toString());
if (idx != 1)
{
sb.append(", ");
}
}
sb.append(">");
return sb.toString();
}
}
public static class ArrayType
{
Type elementType_;
public ArrayType(Type elementType)
{
elementType_ = elementType;
}
public String toString()
{
return "Array(" + elementType_.toString() + ")";
}
}
}

View File

@ -0,0 +1,25 @@
/* 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.cql.common;
import java.util.ArrayList;
public class ColumnMapExpr extends ArrayList<Pair<OperandDef, OperandDef>>
{
private static final long serialVersionUID = 1L;
};

View File

@ -0,0 +1,171 @@
/**
* 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.cql.common;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.List;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.cql.execution.RuntimeErrorMsg;
import org.apache.cassandra.db.ColumnFamily;
import org.apache.cassandra.db.IColumn;
import org.apache.cassandra.db.Row;
import org.apache.cassandra.service.StorageProxy;
import org.apache.cassandra.service.StorageService;
import org.apache.cassandra.utils.LogUtil;
import org.apache.log4j.Logger;
import org.apache.cassandra.db.*;
/**
* A Row Source Defintion (RSD) for doing a range query on a column map
* (in Standard or Super Column Family).
*/
public class ColumnRangeQueryRSD extends RowSourceDef
{
private final static Logger logger_ = Logger.getLogger(ColumnRangeQueryRSD.class);
private CFMetaData cfMetaData_;
private OperandDef rowKey_;
private OperandDef superColumnKey_;
private int offset_;
private int limit_;
/**
* Set up a range query on column map in a simple column family.
* The column map in a simple column family is identified by the rowKey.
*
* Note: "limit" of -1 is the equivalent of no limit.
* "offset" specifies the number of rows to skip. An offset of 0 implies from the first row.
*/
public ColumnRangeQueryRSD(CFMetaData cfMetaData, OperandDef rowKey, int offset, int limit)
{
cfMetaData_ = cfMetaData;
rowKey_ = rowKey;
superColumnKey_ = null;
offset_ = offset;
limit_ = limit;
}
/**
* Setup a range query on a column map in a super column family.
* The column map in a super column family is identified by the rowKey & superColumnKey.
*
* Note: "limit" of -1 is the equivalent of no limit.
* "offset" specifies the number of rows to skip. An offset of 0 implies the first row.
*/
public ColumnRangeQueryRSD(CFMetaData cfMetaData, ConstantOperand rowKey, ConstantOperand superColumnKey,
int offset, int limit)
{
cfMetaData_ = cfMetaData;
rowKey_ = rowKey;
superColumnKey_ = superColumnKey;
offset_ = offset;
limit_ = limit;
}
public List<Map<String,String>> getRows()
{
String columnFamily_column;
String superColumnKey = null;
if (superColumnKey_ != null)
{
superColumnKey = (String)(superColumnKey_.get());
columnFamily_column = cfMetaData_.cfName + ":" + superColumnKey;
}
else
{
columnFamily_column = cfMetaData_.cfName;
}
Row row = null;
try
{
String key = (String)(rowKey_.get());
row = StorageProxy.readProtocol(cfMetaData_.tableName, key, columnFamily_column,
offset_, limit_, StorageService.ConsistencyLevel.WEAK);
}
catch (Exception e)
{
logger_.error(LogUtil.throwableToString(e));
throw new RuntimeException(RuntimeErrorMsg.GENERIC_ERROR.getMsg());
}
List<Map<String, String>> rows = new LinkedList<Map<String, String>>();
if (row != null)
{
Map<String, ColumnFamily> cfMap = row.getColumnFamilies();
if (cfMap != null && cfMap.size() > 0)
{
ColumnFamily cfamily = cfMap.get(cfMetaData_.cfName);
if (cfamily != null)
{
Collection<IColumn> columns = null;
if (superColumnKey_ != null)
{
// this is the super column case
IColumn column = cfamily.getColumn(superColumnKey);
if (column != null)
columns = column.getSubColumns();
}
else
{
columns = cfamily.getAllColumns();
}
if (columns != null && columns.size() > 0)
{
for (IColumn column : columns)
{
Map<String, String> result = new HashMap<String, String>();
result.put(cfMetaData_.n_columnKey, column.name());
result.put(cfMetaData_.n_columnValue, new String(column.value()));
result.put(cfMetaData_.n_columnTimestamp, Long.toString(column.timestamp()));
rows.add(result);
}
}
}
}
}
return rows;
}
public String explainPlan()
{
return String.format("%s Column Family: Column Range Query: \n" +
" Table Name: %s\n" +
" Column Family: %s\n" +
" RowKey: %s\n" +
"%s" +
" Offset: %d\n" +
" Limit: %d\n" +
" Order By: %s",
cfMetaData_.columnType,
cfMetaData_.tableName,
cfMetaData_.cfName,
rowKey_.explain(),
(superColumnKey_ == null) ? "" : " SuperColumnKey: " + superColumnKey_.explain() + "\n",
offset_, limit_,
cfMetaData_.indexProperty_);
}
}

View File

@ -0,0 +1,43 @@
/**
* 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.cql.common;
/**
* ConstantOperand:
* Represents a literal/constant operand in the CQL statement.
* Lives as part of the shared execution plan.
*/
public class ConstantOperand implements OperandDef
{
Object value_;
public ConstantOperand(Object value)
{
value_ = value;
}
public Object get()
{
return value_;
}
public String explain()
{
return "Constant: '" + value_ + "'";
}
};

View File

@ -0,0 +1,36 @@
/**
* 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.cql.common;
import java.util.List;
import java.util.Map;
public class CqlResult
{
public int errorCode; // 0 - success
public String errorTxt;
public List<Map<String, String>> resultSet;
public CqlResult(List<Map<String, String>> rows)
{
resultSet = rows;
errorTxt = null;
errorCode = 0; // success
}
};

View File

@ -0,0 +1,25 @@
/**
* 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.cql.common;
/**
* This class represents the execution plan for DML (data manipulation language)
* CQL statements.
*/
public abstract class DMLPlan extends Plan {};

View File

@ -0,0 +1,66 @@
/**
* 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.cql.common;
import java.util.*;
import org.apache.log4j.Logger;
/**
* The "Plan" for the EXPLAIN PLAN statement itself!
*
* It is nothing but a simple wrapper around the "Plan" for the statement
* on which an EXPLAIN PLAN has been requested.
*/
public class ExplainPlan extends Plan
{
private final static Logger logger_ = Logger.getLogger(ExplainPlan.class);
// the execution plan for the statement on which an
// EXPLAIN PLAN was requested.
private Plan plan_ = null;
/**
* Construct an ExplainPlan instance for the statement whose
* "plan" has been passed in.
*/
public ExplainPlan(Plan plan)
{
plan_ = plan;
}
public CqlResult execute()
{
String planText = plan_.explainPlan();
List<Map<String, String>> rows = new LinkedList<Map<String, String>>();
Map<String, String> row = new HashMap<String, String>();
row.put("PLAN", planText);
rows.add(row);
return new CqlResult(rows);
}
public String explainPlan()
{
// We never expect this method to get invoked for ExplainPlan instances
// (i.e. those that correspond to the EXPLAIN PLAN statement).
logger_.error("explainPlan() invoked on an ExplainPlan instance");
return null;
}
}

View File

@ -0,0 +1,33 @@
/**
* 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.cql.common;
/**
* OperandDef:
*
* The abstract definition of an operand (i.e. data item) in
* CQL compiler/runtime. Examples, include a Constant operand
* or a Bind operand. This is the part of an operand definition
* that lives in the share-able execution plan.
*/
public abstract interface OperandDef
{
public abstract Object get();
public abstract String explain();
};

View File

@ -0,0 +1,53 @@
/**
* 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.cql.common;
/* Would have expected java.util.* to have this class!
* Code cut-paste from wikipedia.
*/
/**
* Generic for representing a "typed" 2-tuple.
*/
public class Pair<T, S>
{
public Pair(T f, S s)
{
first = f;
second = s;
}
public T getFirst()
{
return first;
}
public S getSecond()
{
return second;
}
public String toString()
{
return "(" + first.toString() + ", " + second.toString() + ")";
}
private T first;
private S second;
}

View File

@ -0,0 +1,30 @@
/**
* 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.cql.common;
/**
* Abstract class representing the shared execution plan for a CQL
* statement (query or DML operation).
*
*/
public abstract class Plan
{
public abstract CqlResult execute();
public abstract String explainPlan();
}

View File

@ -0,0 +1,53 @@
/**
* 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.cql.common;
import org.apache.log4j.Logger;
/**
* This class represents the execution plan for Query (data retrieval) statement.
*/
public class QueryPlan extends Plan
{
private final static Logger logger_ = Logger.getLogger(QueryPlan.class);
public RowSourceDef root; // the root of the row source tree
public QueryPlan(RowSourceDef rwsDef)
{
root = rwsDef;
}
public CqlResult execute()
{
if (root != null)
{
return new CqlResult(root.getRows());
}
else
logger_.error("No rowsource to execute");
return null;
}
public String explainPlan()
{
return root.explainPlan();
}
}

View File

@ -0,0 +1,48 @@
/**
* 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.cql.common;
import java.util.List;
import java.util.Map;
/**
* The abstract notion of a row source definition. A row source
* is literally just anything that returns rows back.
*
* The concrete implementations of row source might be things like a
* column family row source, a "super column family" row source,
* a table row source, etc.
*
* Note: Instances of sub-classes of this class are part of the "shared"
* execution plan of CQL. And hence they should not contain any mutable
* (i.e. session specific) execution state. Mutable state, such a bind
* variable values (corresponding to say a rowKey or a column Key) are
* note part of the RowSourceDef tree.
*
* [Eventually the notion of a "mutable" portion of the RowSource (RowSourceMut)
* will be introduced to hold session-specific execution state of the RowSource.
* For example, this would be needed when implementing iterator style rowsources
* that yields rows back one at a time as opposed to returning them in one
* shot.]
*/
public abstract class RowSourceDef
{
public abstract List<Map<String,String>> getRows();
public abstract String explainPlan();
}

View File

@ -0,0 +1,133 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.cql.common;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.cql.execution.RuntimeErrorMsg;
import org.apache.cassandra.db.RowMutation;
import org.apache.cassandra.service.StorageProxy;
import org.apache.cassandra.utils.LogUtil;
import org.apache.log4j.Logger;
import org.apache.cassandra.cql.execution.*;
import org.apache.cassandra.db.*;
import org.apache.cassandra.service.*;
/**
* Execution plan for batch setting a set of columns in a Simple/Super column family.
* SET table.standard_cf[<rowKey>] = <columnMapExpr>;
* SET table.super_cf[<rowKey>][<superColumn>] = <columnMapExpr>;
*/
public class SetColumnMap extends DMLPlan
{
private final static Logger logger_ = Logger.getLogger(SetUniqueKey.class);
private CFMetaData cfMetaData_;
private OperandDef rowKey_;
private OperandDef superColumnKey_;
private ColumnMapExpr columnMapExpr_;
/**
* construct an execution plan node to set the column map for a Standard Column Family.
*
* SET table.standard_cf[<rowKey>] = <columnMapExpr>;
*/
public SetColumnMap(CFMetaData cfMetaData, OperandDef rowKey, ColumnMapExpr columnMapExpr)
{
cfMetaData_ = cfMetaData;
rowKey_ = rowKey;
superColumnKey_ = null;
columnMapExpr_ = columnMapExpr;
}
/**
* Construct an execution plan node to set the column map for a Super Column Family
*
* SET table.super_cf[<rowKey>][<superColumn>] = <columnMapExpr>;
*/
public SetColumnMap(CFMetaData cfMetaData, OperandDef rowKey, OperandDef superColumnKey, ColumnMapExpr columnMapExpr)
{
cfMetaData_ = cfMetaData;
rowKey_ = rowKey;
superColumnKey_ = superColumnKey;
columnMapExpr_ = columnMapExpr;
}
public CqlResult execute()
{
String columnFamily_column;
if (superColumnKey_ != null)
{
String superColumnKey = (String)(superColumnKey_.get());
columnFamily_column = cfMetaData_.cfName + ":" + superColumnKey + ":";
}
else
{
columnFamily_column = cfMetaData_.cfName + ":";
}
try
{
RowMutation rm = new RowMutation(cfMetaData_.tableName, (String)(rowKey_.get()));
long time = System.currentTimeMillis();
for (Pair<OperandDef, OperandDef> entry : columnMapExpr_)
{
OperandDef columnKey = entry.getFirst();
OperandDef value = entry.getSecond();
rm.add(columnFamily_column + (String)(columnKey.get()), ((String)value.get()).getBytes(), time);
}
StorageProxy.insert(rm);
}
catch (Exception e)
{
logger_.error(LogUtil.throwableToString(e));
throw new RuntimeException(RuntimeErrorMsg.GENERIC_ERROR.getMsg());
}
return null;
}
public String explainPlan()
{
StringBuffer sb = new StringBuffer();
String prefix =
String.format("%s Column Family: Batch SET a set of columns: \n" +
" Table Name: %s\n" +
" Column Famly: %s\n" +
" RowKey: %s\n" +
"%s",
cfMetaData_.columnType,
cfMetaData_.tableName,
cfMetaData_.cfName,
rowKey_.explain(),
(superColumnKey_ == null) ? "" : " SuperColumnKey: " + superColumnKey_.explain() + "\n");
for (Pair<OperandDef, OperandDef> entry : columnMapExpr_)
{
OperandDef columnKey = entry.getFirst();
OperandDef value = entry.getSecond();
sb.append(String.format(" ColumnKey: %s\n" +
" Value: %s\n",
columnKey.explain(), value.explain()));
}
return prefix + sb.toString();
}
}

View File

@ -0,0 +1,119 @@
/**
* 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.cql.common;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.cql.execution.RuntimeErrorMsg;
import org.apache.cassandra.db.RowMutation;
import org.apache.cassandra.service.StorageProxy;
import org.apache.cassandra.utils.LogUtil;
import org.apache.log4j.Logger;
import org.apache.cassandra.cql.execution.*;
/**
* Execution plan for batch setting a set of super columns in a Super column family.
* SET table.super_cf[<rowKey>] = <superColumnMapExpr>;
*/
public class SetSuperColumnMap extends DMLPlan
{
private final static Logger logger_ = Logger.getLogger(SetUniqueKey.class);
private CFMetaData cfMetaData_;
private OperandDef rowKey_;
private SuperColumnMapExpr superColumnMapExpr_;
/**
* construct an execution plan node to batch set a bunch of super columns in a
* super column family.
*
* SET table.super_cf[<rowKey>] = <superColumnMapExpr>;
*/
public SetSuperColumnMap(CFMetaData cfMetaData, OperandDef rowKey, SuperColumnMapExpr superColumnMapExpr)
{
cfMetaData_ = cfMetaData;
rowKey_ = rowKey;
superColumnMapExpr_ = superColumnMapExpr;
}
public CqlResult execute()
{
try
{
RowMutation rm = new RowMutation(cfMetaData_.tableName, (String)(rowKey_.get()));
long time = System.currentTimeMillis();
for (Pair<OperandDef, ColumnMapExpr> superColumn : superColumnMapExpr_)
{
OperandDef superColumnKey = superColumn.getFirst();
ColumnMapExpr columnMapExpr = superColumn.getSecond();
String columnFamily_column = cfMetaData_.cfName + ":" + (String)(superColumnKey.get()) + ":";
for (Pair<OperandDef, OperandDef> entry : columnMapExpr)
{
OperandDef columnKey = entry.getFirst();
OperandDef value = entry.getSecond();
rm.add(columnFamily_column + (String)(columnKey.get()), ((String)value.get()).getBytes(), time);
}
}
StorageProxy.insert(rm);
}
catch (Exception e)
{
logger_.error(LogUtil.throwableToString(e));
throw new RuntimeException(RuntimeErrorMsg.GENERIC_ERROR.getMsg());
}
return null;
}
public String explainPlan()
{
StringBuffer sb = new StringBuffer();
String prefix =
String.format("%s Column Family: Batch SET a set of Super Columns: \n" +
" Table Name: %s\n" +
" Column Famly: %s\n" +
" RowKey: %s\n",
cfMetaData_.columnType,
cfMetaData_.tableName,
cfMetaData_.cfName,
rowKey_.explain());
for (Pair<OperandDef, ColumnMapExpr> superColumn : superColumnMapExpr_)
{
OperandDef superColumnKey = superColumn.getFirst();
ColumnMapExpr columnMapExpr = superColumn.getSecond();
for (Pair<OperandDef, OperandDef> entry : columnMapExpr)
{
OperandDef columnKey = entry.getFirst();
OperandDef value = entry.getSecond();
sb.append(String.format(" SuperColumnKey: %s\n" +
" ColumnKey: %s\n" +
" Value: %s\n",
superColumnKey.explain(),
columnKey.explain(),
value.explain()));
}
}
return prefix + sb.toString();
}
}

View File

@ -0,0 +1,118 @@
/**
* 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.cql.common;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.cql.execution.RuntimeErrorMsg;
import org.apache.cassandra.db.RowMutation;
import org.apache.cassandra.service.StorageProxy;
import org.apache.cassandra.utils.LogUtil;
import org.apache.log4j.Logger;
/**
* Execution plan for setting a specific column in a Simple/Super column family.
* SET table.standard_cf[<rowKey>][<columnKey>] = <value>;
* SET table.super_cf[<rowKey>][<superColumnKey>][<columnKey>] = <value>;
*/
public class SetUniqueKey extends DMLPlan
{
private final static Logger logger_ = Logger.getLogger(SetUniqueKey.class);
private CFMetaData cfMetaData_;
private OperandDef rowKey_;
private OperandDef superColumnKey_;
private OperandDef columnKey_;
private OperandDef value_;
/**
* Construct an execution plan for setting a column in a simple column family
*
* SET table.standard_cf[<rowKey>][<columnKey>] = <value>;
*/
public SetUniqueKey(CFMetaData cfMetaData, OperandDef rowKey, OperandDef columnKey, OperandDef value)
{
cfMetaData_ = cfMetaData;
rowKey_ = rowKey;
columnKey_ = columnKey;
superColumnKey_ = null;
value_ = value;
}
/**
* Construct execution plan for setting a column in a super column family.
*
* SET table.super_cf[<rowKey>][<superColumnKey>][<columnKey>] = <value>;
*/
public SetUniqueKey(CFMetaData cfMetaData, OperandDef rowKey, OperandDef superColumnKey, OperandDef columnKey, OperandDef value)
{
cfMetaData_ = cfMetaData;
rowKey_ = rowKey;
superColumnKey_ = superColumnKey;
columnKey_ = columnKey;
value_ = value;
}
public CqlResult execute()
{
String columnKey = (String)(columnKey_.get());
String columnFamily_column;
if (superColumnKey_ != null)
{
String superColumnKey = (String)(superColumnKey_.get());
columnFamily_column = cfMetaData_.cfName + ":" + superColumnKey + ":" + columnKey;
}
else
{
columnFamily_column = cfMetaData_.cfName + ":" + columnKey;
}
try
{
RowMutation rm = new RowMutation(cfMetaData_.tableName, (String)(rowKey_.get()));
rm.add(columnFamily_column, ((String)value_.get()).getBytes(), System.currentTimeMillis());
StorageProxy.insert(rm);
}
catch (Exception e)
{
logger_.error(LogUtil.throwableToString(e));
throw new RuntimeException(RuntimeErrorMsg.GENERIC_ERROR.getMsg());
}
return null;
}
public String explainPlan()
{
return
String.format("%s Column Family: Unique Key SET: \n" +
" Table Name: %s\n" +
" Column Famly: %s\n" +
" RowKey: %s\n" +
"%s" +
" ColumnKey: %s\n" +
" Value: %s\n",
cfMetaData_.columnType,
cfMetaData_.tableName,
cfMetaData_.cfName,
rowKey_.explain(),
(superColumnKey_ == null) ? "" : " SuperColumnKey: " + superColumnKey_.explain() + "\n",
columnKey_.explain(),
value_.explain());
}
}

View File

@ -0,0 +1,25 @@
/* 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.cql.common;
import java.util.ArrayList;
public class SuperColumnMapExpr extends ArrayList<Pair<OperandDef, ColumnMapExpr>>
{
private static final long serialVersionUID = 1L;
};

View File

@ -0,0 +1,132 @@
/**
* 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.cql.common;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.List;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.cql.execution.RuntimeErrorMsg;
import org.apache.cassandra.db.ColumnFamily;
import org.apache.cassandra.db.IColumn;
import org.apache.cassandra.db.Row;
import org.apache.cassandra.service.StorageProxy;
import org.apache.cassandra.service.StorageService;
import org.apache.cassandra.service.column_t;
import org.apache.cassandra.service.superColumn_t;
import org.apache.cassandra.utils.LogUtil;
import org.apache.log4j.Logger;
import org.apache.cassandra.db.*;
/**
* A Row Source Defintion (RSD) for doing a super column range query on a Super Column Family.
*/
public class SuperColumnRangeQueryRSD extends RowSourceDef
{
private final static Logger logger_ = Logger.getLogger(SuperColumnRangeQueryRSD.class);
private CFMetaData cfMetaData_;
private OperandDef rowKey_;
private OperandDef superColumnKey_;
private int offset_;
private int limit_;
/**
* Set up a range query on super column map in a super column family.
* The super column map is identified by the rowKey.
*
* Note: "limit" of -1 is the equivalent of no limit.
* "offset" specifies the number of rows to skip.
* An offset of 0 implies from the first row.
*/
public SuperColumnRangeQueryRSD(CFMetaData cfMetaData, OperandDef rowKey, int offset, int limit)
{
cfMetaData_ = cfMetaData;
rowKey_ = rowKey;
offset_ = offset;
limit_ = limit;
}
public List<Map<String,String>> getRows()
{
Row row = null;
try
{
String key = (String)(rowKey_.get());
row = StorageProxy.readProtocol(cfMetaData_.tableName, key, cfMetaData_.cfName,
offset_, limit_, StorageService.ConsistencyLevel.WEAK);
}
catch (Exception e)
{
logger_.error(LogUtil.throwableToString(e));
throw new RuntimeException(RuntimeErrorMsg.GENERIC_ERROR.getMsg());
}
List<Map<String, String>> rows = new LinkedList<Map<String, String>>();
if (row != null)
{
Map<String, ColumnFamily> cfMap = row.getColumnFamilies();
if (cfMap != null && cfMap.size() > 0)
{
ColumnFamily cfamily = cfMap.get(cfMetaData_.cfName);
if (cfamily != null)
{
Collection<IColumn> columns = cfamily.getAllColumns();
if (columns != null && columns.size() > 0)
{
for (IColumn column : columns)
{
Collection<IColumn> subColumns = column.getSubColumns();
for( IColumn subColumn : subColumns )
{
Map<String, String> result = new HashMap<String, String>();
result.put(cfMetaData_.n_superColumnKey, column.name());
result.put(cfMetaData_.n_columnKey, subColumn.name());
result.put(cfMetaData_.n_columnValue, new String(subColumn.value()));
result.put(cfMetaData_.n_columnTimestamp, Long.toString(subColumn.timestamp()));
rows.add(result);
}
}
}
}
}
}
return rows;
}
public String explainPlan()
{
return String.format("%s Column Family: Super Column Range Query: \n" +
" Table Name: %s\n" +
" Column Family: %s\n" +
" RowKey: %s\n" +
" Offset: %d\n" +
" Limit: %d\n" +
" Order By: %s",
cfMetaData_.columnType,
cfMetaData_.tableName,
cfMetaData_.cfName,
rowKey_.explain(),
offset_, limit_,
cfMetaData_.indexProperty_);
}
}

View File

@ -0,0 +1,165 @@
/**
* 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.cql.common;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.List;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.cql.execution.RuntimeErrorMsg;
import org.apache.cassandra.db.ColumnFamily;
import org.apache.cassandra.db.IColumn;
import org.apache.cassandra.db.Row;
import org.apache.cassandra.service.StorageProxy;
import org.apache.cassandra.service.StorageService;
import org.apache.cassandra.utils.LogUtil;
import org.apache.log4j.Logger;
import org.apache.cassandra.db.*;
/**
* A Row Source Defintion (RSD) for looking up a unique column within a column family.
*/
public class UniqueKeyQueryRSD extends RowSourceDef
{
private final static Logger logger_ = Logger.getLogger(UniqueKeyQueryRSD.class);
private CFMetaData cfMetaData_;
private OperandDef rowKey_;
private OperandDef superColumnKey_;
private OperandDef columnKey_;
// super column family
public UniqueKeyQueryRSD(CFMetaData cfMetaData, OperandDef rowKey, OperandDef superColumnKey, OperandDef columnKey)
{
cfMetaData_ = cfMetaData;
rowKey_ = rowKey;
superColumnKey_ = superColumnKey;
columnKey_ = columnKey;
}
// simple column family
public UniqueKeyQueryRSD(CFMetaData cfMetaData, OperandDef rowKey, OperandDef columnKey)
{
cfMetaData_ = cfMetaData;
rowKey_ = rowKey;
columnKey_ = columnKey;
superColumnKey_ = null;
}
// specific column lookup
public List<Map<String,String>> getRows() throws RuntimeException
{
String columnKey = (String)(columnKey_.get());
String columnFamily_column;
String superColumnKey = null;
if (superColumnKey_ != null)
{
superColumnKey = (String)(superColumnKey_.get());
columnFamily_column = cfMetaData_.cfName + ":" + superColumnKey + ":" + columnKey;
}
else
{
columnFamily_column = cfMetaData_.cfName + ":" + columnKey;
}
Row row = null;
try
{
String key = (String)(rowKey_.get());
row = StorageProxy.readProtocol(cfMetaData_.tableName, key, columnFamily_column, -1,
Integer.MAX_VALUE, StorageService.ConsistencyLevel.WEAK);
}
catch (Exception e)
{
logger_.error(LogUtil.throwableToString(e));
throw new RuntimeException(RuntimeErrorMsg.GENERIC_ERROR.getMsg());
}
if (row != null)
{
Map<String, ColumnFamily> cfMap = row.getColumnFamilies();
if (cfMap != null && cfMap.size() > 0)
{
ColumnFamily cfamily = cfMap.get(cfMetaData_.cfName);
if (cfamily != null)
{
Collection<IColumn> columns = null;
if (superColumnKey_ != null)
{
// this is the super column case
IColumn column = cfamily.getColumn(superColumnKey);
if (column != null)
columns = column.getSubColumns();
}
else
{
columns = cfamily.getAllColumns();
}
if (columns != null && columns.size() > 0)
{
if (columns.size() > 1)
{
// We are looking up by a rowKey & columnKey. There should
// be at most one column that matches. If we find more than
// one, then it is an internal error.
throw new RuntimeException(RuntimeErrorMsg.INTERNAL_ERROR.getMsg("Too many columns found for: " + columnKey));
}
for (IColumn column : columns)
{
List<Map<String, String>> rows = new LinkedList<Map<String, String>>();
Map<String, String> result = new HashMap<String, String>();
result.put(cfMetaData_.n_columnKey, column.name());
result.put(cfMetaData_.n_columnValue, new String(column.value()));
result.put(cfMetaData_.n_columnTimestamp, Long.toString(column.timestamp()));
rows.add(result);
// at this point, due to the prior checks, we are guaranteed that
// there is only one item in "columns".
return rows;
}
return null;
}
}
}
}
throw new RuntimeException(RuntimeErrorMsg.NO_DATA_FOUND.getMsg());
}
public String explainPlan()
{
return String.format("%s Column Family: Unique Key Query: \n" +
" Table Name: %s\n" +
" Column Famly: %s\n" +
" RowKey: %s\n" +
"%s" +
" ColumnKey: %s",
cfMetaData_.columnType,
cfMetaData_.tableName,
cfMetaData_.cfName,
rowKey_.explain(),
(superColumnKey_ == null) ? "" : " SuperColumnKey: " + superColumnKey_.explain() + "\n",
columnKey_.explain());
}
}

View File

@ -0,0 +1,62 @@
/**
* 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.cql.common;
public class Utils
{
/*
* Strips leading and trailing "'" characters, and handles
* and escaped characters such as \n, \r, etc.
* [Shameless clone from hive.]
*/
public static String unescapeSQLString(String b)
{
assert(b.charAt(0) == '\'');
assert(b.charAt(b.length()-1) == '\'');
StringBuilder sb = new StringBuilder(b.length());
for (int i=1; i+1<b.length(); i++)
{
if (b.charAt(i) == '\\' && i+2<b.length())
{
char n=b.charAt(i+1);
switch(n)
{
case '0': sb.append("\0"); break;
case '\'': sb.append("'"); break;
case '"': sb.append("\""); break;
case 'b': sb.append("\b"); break;
case 'n': sb.append("\n"); break;
case 'r': sb.append("\r"); break;
case 't': sb.append("\t"); break;
case 'Z': sb.append("\u001A"); break;
case '\\': sb.append("\\"); break;
case '%': sb.append("%"); break;
case '_': sb.append("_"); break;
default: sb.append(n);
}
}
else
{
sb.append(b.charAt(i));
}
}
return sb.toString();
}
}

View File

@ -0,0 +1,70 @@
/**
* 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.cql.compiler.common;
import org.antlr.runtime.tree.CommonTree;
/**
* List of error messages thrown by the CQL Compiler
**/
public enum CompilerErrorMsg
{
// Error messages with String.format() style format specifiers
GENERIC_ERROR("CQL Compilation Error"),
INTERNAL_ERROR("CQL Compilation Internal Error"),
INVALID_TABLE("Table '%s' does not exist"),
INVALID_COLUMN_FAMILY("Column Family '%s' not found in table '%s'"),
TOO_MANY_DIMENSIONS("Too many dimensions specified for %s Column Family"),
INVALID_TYPE("Expression is of invalid type")
;
private String mesg;
CompilerErrorMsg(String mesg)
{
this.mesg = mesg;
}
private static String getLineAndPosition(CommonTree tree)
{
if (tree.getChildCount() == 0)
{
return tree.getToken().getLine() + ":" + tree.getToken().getCharPositionInLine();
}
return getLineAndPosition((CommonTree)tree.getChild(0));
}
// Returns the formatted error message. Derives line/position information
// from the "tree" node passed in.
public String getMsg(CommonTree tree, Object... args)
{
// We allocate another array since we want to add line and position as an
// implicit additional first argument to pass on to String.format.
Object[] newArgs = new Object[args.length + 1];
newArgs[0] = getLineAndPosition(tree);
System.arraycopy(args, 0, newArgs, 1, args.length);
// note: mesg itself might contain other format specifiers...
return String.format("line %s " + mesg, newArgs);
}
String getMsg()
{
return mesg;
}
}

View File

@ -0,0 +1,149 @@
/**
* 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.cql.compiler.common;
import org.apache.cassandra.cql.common.*;
import org.apache.cassandra.cql.compiler.parse.*;
import org.apache.cassandra.cql.compiler.sem.*;
import java.util.ArrayList;
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.apache.cassandra.cql.common.Plan;
import org.apache.cassandra.cql.compiler.parse.CqlLexer;
import org.apache.cassandra.cql.compiler.parse.CqlParser;
import org.apache.cassandra.cql.compiler.parse.ParseError;
import org.apache.cassandra.cql.compiler.parse.ParseException;
import org.apache.cassandra.cql.compiler.sem.SemanticException;
import org.apache.cassandra.cql.compiler.sem.SemanticPhase;
public class CqlCompiler
{
// ANTLR does not provide case-insensitive tokenization support
// out of the box. So we override the LA (lookahead) function
// of the ANTLRStringStream class. Note: This doesn't change the
// token text-- but just relaxes the matching rules to match
// in upper case. [Logic borrowed from Hive code.]
//
// Also see discussion on this topic in:
// http://www.antlr.org/wiki/pages/viewpage.action?pageId=1782.
public class ANTLRNoCaseStringStream extends ANTLRStringStream
{
public ANTLRNoCaseStringStream(String input)
{
super(input);
}
public int LA(int i)
{
int returnChar = super.LA(i);
if (returnChar == CharStream.EOF)
{
return returnChar;
}
else if (returnChar == 0)
{
return returnChar;
}
return Character.toUpperCase((char)returnChar);
}
}
// Override CQLParser. This gives flexibility in altering default error
// messages as well as accumulating multiple errors.
public class CqlParserX extends CqlParser
{
private ArrayList<ParseError> errors;
public CqlParserX(TokenStream input)
{
super(input);
errors = new ArrayList<ParseError>();
}
protected void mismatch(IntStream input, int ttype, BitSet follow) throws RecognitionException
{
throw new MismatchedTokenException(ttype, input);
}
public void recoverFromMismatchedSet(IntStream input,
RecognitionException re,
BitSet follow) throws RecognitionException
{
throw re;
}
public void displayRecognitionError(String[] tokenNames,
RecognitionException e)
{
errors.add(new ParseError(this, e, tokenNames));
}
public ArrayList<ParseError> getErrors()
{
return errors;
}
}
// Compile a CQL query
public Plan compileQuery(String query) throws ParseException, SemanticException
{
CommonTree queryTree = null;
CqlLexer lexer = null;
CqlParserX parser = null;
CommonTokenStream tokens = null;
ANTLRStringStream input = new ANTLRNoCaseStringStream(query);
lexer = new CqlLexer(input);
tokens = new CommonTokenStream(lexer);
parser = new CqlParserX(tokens);
// built AST
try
{
queryTree = (CommonTree)(parser.root().getTree());
}
catch (RecognitionException e)
{
throw new ParseException(parser.getErrors());
}
catch (RewriteEmptyStreamException e)
{
throw new ParseException(parser.getErrors());
}
if (!parser.getErrors().isEmpty())
{
throw new ParseException(parser.getErrors());
}
if (!parser.errors.isEmpty())
{
throw new ParseException("parser error");
}
// Semantic analysis and code-gen.
// Eventually, I anticipate, I'll be forking these off into two separate phases.
return SemanticPhase.doSemanticAnalysis(queryTree);
}
}

View File

@ -0,0 +1,308 @@
/**
* 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.
*/
// ANTLR Grammar Definition for Cassandra Query Language (CQL)
//
// CQL is a query language tailored for Cassandra's multi-level (or
// nested-table like) data model where values stored for each key
// can be:
//
// * a simple column map (a 1-level nested table). This is the case
// for a simple column family.
//
// or,
//
// * a supercolumn column map, which in turn contains a column map
// per super column (i.e. a 2-level nested table). This is the case
// for a super column family.
//
// For the common case of key-based data retrieval or storage, CQL
// provides array like get/set syntax, such as:
//
// SET user.profile['99']['name'] = 'joe';
// SET user.profile['99']['age'] = '27';
// GET user.profile['99']['name'];
// GET user.profile['99'];
//
// When additional constraints need to be applied to data being retrieved
// (such as imposing row limits, retrieving counts, retrieving data for
// a subset of super columns or columns and son on) CQL falls back to more
// traditional SQL-like syntax.
//
// *Note*: The SQL syntax supported by CQL doesn't support the full
// relational algebra. For example, it doesn't have any support for
// joins. It also imposes restrictions on the types of filters and ORDER
// BY clauses it supports-- generally only those queries that can be
// efficiently answered based on data layout are supported. Suppose a column
// family has been configured to store columns in time sorted fashion,
// CQL will not support 'ORDER BY column_name' for such a column family.
//
//
// NOTE: The grammar is in a very rudimentary/prototypish shape right now.
// Will undergo fairly big restructuring in the next checkin.
//
grammar Cql;
options {
output=AST;
ASTLabelType=CommonTree;
backtrack=true;
}
//
// AST Nodes. We use a A_ prefix convention for these AST node names.
//
tokens {
// Top-level AST nodes
// These typically correspond to various top-level CQL statements.
A_DELETE;
A_GET;
A_SELECT;
A_SET;
A_EXPLAIN_PLAN;
// Internal AST nodes
A_COLUMN_ACCESS;
A_COLUMN_MAP_ENTRY;
A_COLUMN_MAP_VALUE;
A_FROM;
A_KEY_IN_LIST;
A_KEY_EXACT_MATCH;
A_LIMIT;
A_OFFSET;
A_ORDER_BY;
A_SUPERCOLUMN_MAP_ENTRY;
A_SUPERCOLUMN_MAP_VALUE;
A_SELECT_CLAUSE;
A_WHERE;
}
@parser::header {
package com.facebook.infrastructure.cql.compiler.parse;
}
@lexer::header {
package com.facebook.infrastructure.cql.compiler.parse;
}
//
// Parser Section
//
// the root node
root
: stmt SEMICOLON? EOF -> stmt
| K_EXPLAIN K_PLAN stmt SEMICOLON? EOF -> ^(A_EXPLAIN_PLAN stmt)
;
stmt
: deleteStmt
| getStmt
| selectStmt
| setStmt
;
getStmt
: K_GET columnSpec -> ^(A_GET columnSpec)
;
setStmt
: K_SET columnSpec '=' valueExpr -> ^(A_SET columnSpec valueExpr)
;
selectStmt
: selectClause
fromClause?
whereClause?
limitClause? -> ^(A_SELECT selectClause fromClause? whereClause? limitClause?)
;
selectClause
: K_SELECT selectList -> ^(A_SELECT_CLAUSE selectList)
;
selectList
: selectListItem (',' selectListItem)*
;
selectListItem
: columnExpression
| '(' selectStmt ')' -> ^(A_SELECT selectStmt)
;
columnExpression
: columnOrSuperColumnName columnExpressionRest;
columnExpressionRest
: /* empty */
| '[' stringVal ']' columnExpressionRest
;
tableExpression
: tableName '.' columnFamilyName '[' stringVal ']';
fromClause
: K_FROM tableExpression -> ^(A_FROM tableExpression)
;
whereClause
: K_WHERE keyInClause -> ^(A_WHERE keyInClause)
| K_WHERE keyExactMatch -> ^(A_WHERE keyExactMatch)
;
keyInClause
: columnOrSuperColumnName K_IN '(' a+=stringVal (',' a+=stringVal)* ')'
-> ^(A_KEY_IN_LIST columnOrSuperColumnName $a+)
;
keyExactMatch
: columnOrSuperColumnName '=' stringVal
-> ^(A_KEY_EXACT_MATCH columnOrSuperColumnName stringVal)
;
limitClause
: K_LIMIT IntegerLiteral -> ^(A_LIMIT IntegerLiteral);
deleteStmt
: K_DELETE columnSpec -> ^(A_DELETE columnSpec)
;
columnSpec
: tableName '.' columnFamilyName '[' rowKey ']'
( '[' a+=columnOrSuperColumnKey ']'
('[' a+=columnOrSuperColumnKey ']')?
)?
-> ^(A_COLUMN_ACCESS tableName columnFamilyName rowKey ($a+)?)
;
tableName: Identifier;
columnFamilyName: Identifier;
valueExpr
: cellValue
| columnMapValue
| superColumnMapValue
;
cellValue
: stringVal;
columnMapValue
: LEFT_BRACE columnMapEntry (COMMA columnMapEntry)* RIGHT_BRACE
-> ^(A_COLUMN_MAP_VALUE columnMapEntry+)
;
superColumnMapValue
: LEFT_BRACE superColumnMapEntry (COMMA superColumnMapEntry)* RIGHT_BRACE
-> ^(A_SUPERCOLUMN_MAP_VALUE superColumnMapEntry+)
;
columnMapEntry
: columnKey ASSOC cellValue -> ^(A_COLUMN_MAP_ENTRY columnKey cellValue)
;
superColumnMapEntry
: superColumnKey ASSOC columnMapValue -> ^(A_SUPERCOLUMN_MAP_ENTRY superColumnKey columnMapValue)
;
columnOrSuperColumnName: Identifier;
rowKey: stringVal;
columnOrSuperColumnKey: stringVal;
columnKey: stringVal;
superColumnKey: stringVal;
// String Values can either be query params (aka bind variables)
// or string literals.
stringVal
: '?' // bind variable
| StringLiteral //
;
//
// Lexer Section
//
// Keywords (in alphabetical order for convenience)
K_BY: 'BY';
K_DELETE: 'DELETE';
K_EXPLAIN: 'EXPLAIN';
K_FROM: 'FROM';
K_GET: 'GET';
K_IN: 'IN';
K_LIMIT: 'LIMIT';
K_OFFSET: 'OFFSET';
K_ORDER: 'ORDER';
K_PLAN: 'PLAN';
K_SELECT: 'SELECT';
K_SET: 'SET';
K_WHERE: 'WHERE';
// private syntactic rules
fragment
Letter
: 'a'..'z'
| 'A'..'Z'
;
fragment
Digit
: '0'..'9'
;
// syntactic Elements
Identifier
: Letter ( Letter | Digit | '_')*
;
//
// Literals
//
// strings: escape single quote ' by repeating it '' (SQL style)
StringLiteral
: '\'' (~'\'')* '\'' ( '\'' (~'\'')* '\'' )*
;
// integer literals
IntegerLiteral
: Digit+
;
//
// miscellaneous syntactic elements
//
WS
: (' '|'\r'|'\t'|'\n') {skip();} // whitepace
;
COMMENT
: '--' (~('\n'|'\r'))* { $channel=HIDDEN; }
| '/*' (options {greedy=false;} : .)* '*/' { $channel=HIDDEN; }
;
ASSOC: '=>';
COMMA: ',';
LEFT_BRACE: '{';
RIGHT_BRACE: '}';
SEMICOLON: ';';

View File

@ -0,0 +1,51 @@
K_EXPLAIN=23
K_OFFSET=41
K_GET=25
K_DELETE=33
A_KEY_EXACT_MATCH=14
K_BY=40
A_SELECT=6
A_SUPERCOLUMN_MAP_VALUE=19
K_SELECT=27
K_LIMIT=31
Identifier=34
K_SET=26
K_WHERE=29
COMMA=36
A_EXPLAIN_PLAN=8
A_LIMIT=15
COMMENT=46
K_ORDER=42
RIGHT_BRACE=37
A_COLUMN_MAP_VALUE=11
SEMICOLON=22
K_IN=30
Digit=44
A_OFFSET=16
A_WHERE=21
K_PLAN=24
A_ORDER_BY=17
K_FROM=28
StringLiteral=39
A_COLUMN_MAP_ENTRY=10
WS=45
A_FROM=12
A_GET=5
LEFT_BRACE=35
A_KEY_IN_LIST=13
A_COLUMN_ACCESS=9
A_SUPERCOLUMN_MAP_ENTRY=18
IntegerLiteral=32
ASSOC=38
A_SELECT_CLAUSE=20
Letter=43
A_DELETE=4
A_SET=7
'?'=53
'='=47
'('=48
'['=50
','=36
'.'=52
')'=49
']'=51

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,100 @@
lexer grammar Cql;
@header {
package com.facebook.infrastructure.cql.compiler.parse;
}
T47 : '=' ;
T48 : '(' ;
T49 : ')' ;
T50 : '[' ;
T51 : ']' ;
T52 : '.' ;
T53 : '?' ;
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 247
K_BY: 'BY';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 248
K_DELETE: 'DELETE';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 249
K_EXPLAIN: 'EXPLAIN';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 250
K_FROM: 'FROM';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 251
K_GET: 'GET';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 252
K_IN: 'IN';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 253
K_LIMIT: 'LIMIT';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 254
K_OFFSET: 'OFFSET';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 255
K_ORDER: 'ORDER';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 256
K_PLAN: 'PLAN';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 257
K_SELECT: 'SELECT';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 258
K_SET: 'SET';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 259
K_WHERE: 'WHERE';
// private syntactic rules
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 262
fragment
Letter
: 'a'..'z'
| 'A'..'Z'
;
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 268
fragment
Digit
: '0'..'9'
;
// syntactic Elements
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 274
Identifier
: Letter ( Letter | Digit | '_')*
;
//
// Literals
//
// strings: escape single quote ' by repeating it '' (SQL style)
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 283
StringLiteral
: '\'' (~'\'')* '\'' ( '\'' (~'\'')* '\'' )*
;
// integer literals
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 288
IntegerLiteral
: Digit+
;
//
// miscellaneous syntactic elements
//
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 295
WS
: (' '|'\r'|'\t'|'\n') {skip();} // whitepace
;
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 299
COMMENT
: '--' (~('\n'|'\r'))* { $channel=HIDDEN; }
| '/*' (options {greedy=false;} : .)* '*/' { $channel=HIDDEN; }
;
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 304
ASSOC: '=>';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 305
COMMA: ',';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 306
LEFT_BRACE: '{';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 307
RIGHT_BRACE: '}';
// $ANTLR src "/home/kannan/fbomb/trunk/fbcode/cassandra/src/com/facebook/infrastructure/cql/compiler/parse/Cql.g" 308
SEMICOLON: ';';

View File

@ -0,0 +1,50 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.cql.compiler.parse;
import org.antlr.runtime.*;
public class ParseError {
private BaseRecognizer br;
private RecognitionException re;
private String[] tokenNames;
public ParseError(BaseRecognizer br, RecognitionException re, String[] tokenNames) {
this.br = br;
this.re = re;
this.tokenNames = tokenNames;
}
public BaseRecognizer getBaseRecognizer() {
return br;
}
public RecognitionException getRecognitionException() {
return re;
}
public String[] getTokenNames() {
return tokenNames;
}
public String getMessage() {
return br.getErrorHeader(re) + " " + br.getErrorMessage(re, tokenNames);
}
}

View File

@ -0,0 +1,57 @@
/**
* 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.cql.compiler.parse;
/**
* Exception from the CQL Parser
*/
import java.util.ArrayList;
public class ParseException extends Exception {
private static final long serialVersionUID = 1L;
ArrayList<ParseError> errors = null;
public ParseException(ArrayList<ParseError> errors)
{
super();
this.errors = errors;
}
public ParseException(String message)
{
super(message);
}
public String getMessage() {
if (errors == null)
return super.getMessage();
StringBuilder sb = new StringBuilder();
for(ParseError err: errors) {
sb.append(err.getMessage());
sb.append("\n");
}
return sb.toString();
}
}

View File

@ -0,0 +1,49 @@
/**
* 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.cql.compiler.sem;
/**
* Exception from the CQL SemanticAnalyzer
*/
public class SemanticException extends Exception
{
private static final long serialVersionUID = 1L;
public SemanticException()
{
super();
}
public SemanticException(String message)
{
super(message);
}
public SemanticException(Throwable cause)
{
super(cause);
}
public SemanticException(String message, Throwable cause)
{
super(message, cause);
}
}

View File

@ -0,0 +1,342 @@
/**
* 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.cql.compiler.sem;
import java.util.Map;
import org.antlr.runtime.tree.CommonTree;
import org.apache.cassandra.cql.common.*;
import org.apache.cassandra.cql.compiler.common.*;
import org.apache.cassandra.cql.compiler.parse.*;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.cql.common.ColumnMapExpr;
import org.apache.cassandra.cql.common.ColumnRangeQueryRSD;
import org.apache.cassandra.cql.common.ConstantOperand;
import org.apache.cassandra.cql.common.ExplainPlan;
import org.apache.cassandra.cql.common.OperandDef;
import org.apache.cassandra.cql.common.Pair;
import org.apache.cassandra.cql.common.Plan;
import org.apache.cassandra.cql.common.QueryPlan;
import org.apache.cassandra.cql.common.RowSourceDef;
import org.apache.cassandra.cql.common.SetColumnMap;
import org.apache.cassandra.cql.common.SetSuperColumnMap;
import org.apache.cassandra.cql.common.SetUniqueKey;
import org.apache.cassandra.cql.common.SuperColumnMapExpr;
import org.apache.cassandra.cql.common.SuperColumnRangeQueryRSD;
import org.apache.cassandra.cql.common.UniqueKeyQueryRSD;
import org.apache.cassandra.cql.common.Utils;
import org.apache.cassandra.cql.compiler.common.CompilerErrorMsg;
import org.apache.cassandra.cql.compiler.parse.CqlParser;
import org.apache.log4j.Logger;
//
// Note: This class is CQL related work in progress.
//
// Currently, this phase combines both semantic analysis and code-gen.
// I expect that as my ideas get refined/cleared up, I'll be drawing
// a more clear distinction between semantic analysis phase and code-gen.
//
public class SemanticPhase
{
private final static Logger logger_ = Logger.getLogger(SemanticPhase.class);
// Current code-gen also happens in this phase!
public static Plan doSemanticAnalysis(CommonTree ast) throws SemanticException
{
Plan plan = null;
logger_.debug("AST: " + ast.toStringTree());
switch (ast.getType())
{
case CqlParser.A_GET:
plan = compileGet(ast);
break;
case CqlParser.A_SET:
plan = compileSet(ast);
break;
case CqlParser.A_DELETE:
compileDelete(ast);
break;
case CqlParser.A_SELECT:
compileSelect(ast);
break;
case CqlParser.A_EXPLAIN_PLAN:
// Case: EXPLAN PLAN <stmt>
// first, generate a plan for <stmt>
// and then, wrapper it with a special ExplainPlan plan
// whose execution will result in an explain plan rather
// than a normal execution of the statement.
plan = doSemanticAnalysis((CommonTree)(ast.getChild(0)));
plan = new ExplainPlan(plan);
break;
default:
// Unhandled AST node. Raise an internal error.
throw new SemanticException(CompilerErrorMsg.INTERNAL_ERROR.getMsg(ast, "Unknown Node Type: " + ast.getType()));
}
return plan;
}
/**
* Given a CommonTree AST node of type, A_COLUMN_ACCESS related functions, do semantic
* checking to ensure table name, column family name, and number of key dimensions
* specified are all valid.
*/
private static CFMetaData getColumnFamilyInfo(CommonTree ast) throws SemanticException
{
assert(ast.getType() == CqlParser.A_COLUMN_ACCESS);
CommonTree columnFamilyNode = (CommonTree)(ast.getChild(1));
CommonTree tableNode = (CommonTree)(ast.getChild(0));
String columnFamily = columnFamilyNode.getText();
String table = tableNode.getText();
Map<String, CFMetaData> columnFamilies = DatabaseDescriptor.getTableMetaData(table);
if (columnFamilies == null)
{
throw new SemanticException(CompilerErrorMsg.INVALID_TABLE.getMsg(ast, table));
}
CFMetaData cfMetaData = columnFamilies.get(columnFamily);
if (cfMetaData == null)
{
throw new SemanticException(CompilerErrorMsg.INVALID_COLUMN_FAMILY.getMsg(ast, columnFamily, table));
}
// Once you have drilled down to a row using a rowKey, a super column
// map can be indexed only 2 further levels deep; and a column map may
// be indexed up to 1 level deep.
int dimensions = numColumnDimensions(ast);
if (("Super".equals(cfMetaData.columnType) && (dimensions > 2)) ||
("Standard".equals(cfMetaData.columnType) && dimensions > 1))
{
throw new SemanticException(CompilerErrorMsg.TOO_MANY_DIMENSIONS.getMsg(ast, cfMetaData.columnType));
}
return cfMetaData;
}
private static String getRowKey(CommonTree ast)
{
assert(ast.getType() == CqlParser.A_COLUMN_ACCESS);
return Utils.unescapeSQLString(ast.getChild(2).getText());
}
private static int numColumnDimensions(CommonTree ast)
{
// Skip over table name, column family and rowKey
return ast.getChildCount() - 3;
}
// Returns the pos'th (0-based index) column specifier in the astNode
private static String getColumn(CommonTree ast, int pos)
{
// Skip over table name, column family and rowKey
return Utils.unescapeSQLString(ast.getChild(pos + 3).getText());
}
// Compile a GET statement
private static Plan compileGet(CommonTree ast) throws SemanticException
{
int childCount = ast.getChildCount();
assert(childCount == 1);
CommonTree columnFamilySpec = (CommonTree)ast.getChild(0);
assert(columnFamilySpec.getType() == CqlParser.A_COLUMN_ACCESS);
CFMetaData cfMetaData = getColumnFamilyInfo(columnFamilySpec);
ConstantOperand rowKey = new ConstantOperand(getRowKey(columnFamilySpec));
int dimensionCnt = numColumnDimensions(columnFamilySpec);
RowSourceDef rwsDef;
if ("Super".equals(cfMetaData.columnType))
{
if (dimensionCnt > 2)
{
// We don't expect this case to arise, since Cql.g grammar disallows this.
// therefore, raise this case as an "internal error".
throw new SemanticException(CompilerErrorMsg.INTERNAL_ERROR.getMsg(columnFamilySpec));
}
if (dimensionCnt == 2)
{
// Case: table.super_cf[<rowKey>][<superColumnKey>][<columnKey>]
ConstantOperand superColumnKey = new ConstantOperand(getColumn(columnFamilySpec, 0));
ConstantOperand columnKey = new ConstantOperand(getColumn(columnFamilySpec, 1));
rwsDef = new UniqueKeyQueryRSD(cfMetaData, rowKey, superColumnKey, columnKey);
}
else if (dimensionCnt == 1)
{
// Case: table.super_cf[<rowKey>][<superColumnKey>]
ConstantOperand superColumnKey = new ConstantOperand(getColumn(columnFamilySpec, 0));
rwsDef = new ColumnRangeQueryRSD(cfMetaData, rowKey, superColumnKey, -1, Integer.MAX_VALUE);
}
else
{
// Case: table.super_cf[<rowKey>]
rwsDef = new SuperColumnRangeQueryRSD(cfMetaData, rowKey, -1, Integer.MAX_VALUE);
}
}
else // Standard Column Family
{
if (dimensionCnt == 1)
{
// Case: table.standard_cf[<rowKey>][<columnKey>]
ConstantOperand columnKey = new ConstantOperand(getColumn(columnFamilySpec, 0));
rwsDef = new UniqueKeyQueryRSD(cfMetaData, rowKey, columnKey);
}
else
{
// Case: table.standard_cf[<rowKey>]
logger_.assertLog((dimensionCnt == 0), "invalid dimensionCnt: " + dimensionCnt);
rwsDef = new ColumnRangeQueryRSD(cfMetaData, rowKey, -1, Integer.MAX_VALUE);
}
}
return new QueryPlan(rwsDef);
}
private static OperandDef getSimpleExpr(CommonTree ast) throws SemanticException
{
int type = ast.getType();
// for now, the only simple expressions support are of string type
if (type != CqlParser.StringLiteral)
{
throw new SemanticException(CompilerErrorMsg.INVALID_TYPE.getMsg(ast));
}
return new ConstantOperand(Utils.unescapeSQLString(ast.getText()));
}
private static ColumnMapExpr getColumnMapExpr(CommonTree ast) throws SemanticException
{
int type = ast.getType();
if (type != CqlParser.A_COLUMN_MAP_VALUE)
{
throw new SemanticException(CompilerErrorMsg.INVALID_TYPE.getMsg(ast));
}
int size = ast.getChildCount();
ColumnMapExpr result = new ColumnMapExpr();
for (int idx = 0; idx < size; idx++)
{
CommonTree entryNode = (CommonTree)(ast.getChild(idx));
OperandDef columnKey = getSimpleExpr((CommonTree)(entryNode.getChild(0)));
OperandDef columnValue = getSimpleExpr((CommonTree)(entryNode.getChild(1)));
Pair<OperandDef, OperandDef> entry = new Pair<OperandDef, OperandDef>(columnKey, columnValue);
result.add(entry);
}
return result;
}
private static SuperColumnMapExpr getSuperColumnMapExpr(CommonTree ast) throws SemanticException
{
int type = ast.getType();
if (type != CqlParser.A_SUPERCOLUMN_MAP_VALUE)
{
throw new SemanticException(CompilerErrorMsg.INVALID_TYPE.getMsg(ast));
}
int size = ast.getChildCount();
SuperColumnMapExpr result = new SuperColumnMapExpr();
for (int idx = 0; idx < size; idx++)
{
CommonTree entryNode = (CommonTree)(ast.getChild(idx));
OperandDef superColumnKey = getSimpleExpr((CommonTree)(entryNode.getChild(0)));
ColumnMapExpr columnMapExpr = getColumnMapExpr((CommonTree)(entryNode.getChild(1)));
Pair<OperandDef, ColumnMapExpr> entry = new Pair<OperandDef, ColumnMapExpr>(superColumnKey, columnMapExpr);
result.add(entry);
}
return result;
}
// compile a SET statement
private static Plan compileSet(CommonTree ast) throws SemanticException
{
int childCount = ast.getChildCount();
assert(childCount == 2);
CommonTree columnFamilySpec = (CommonTree)ast.getChild(0);
assert(columnFamilySpec.getType() == CqlParser.A_COLUMN_ACCESS);
CFMetaData cfMetaData = getColumnFamilyInfo(columnFamilySpec);
ConstantOperand rowKey = new ConstantOperand(getRowKey(columnFamilySpec));
int dimensionCnt = numColumnDimensions(columnFamilySpec);
CommonTree valueNode = (CommonTree)(ast.getChild(1));
Plan plan = null;
if ("Super".equals(cfMetaData.columnType))
{
if (dimensionCnt == 2)
{
// Case: set table.super_cf['key']['supercolumn']['column'] = 'value'
OperandDef value = getSimpleExpr(valueNode);
ConstantOperand superColumnKey = new ConstantOperand(getColumn(columnFamilySpec, 0));
ConstantOperand columnKey = new ConstantOperand(getColumn(columnFamilySpec, 1));
plan = new SetUniqueKey(cfMetaData, rowKey, superColumnKey, columnKey, value);
}
else if (dimensionCnt == 1)
{
// Case: set table.super_cf['key']['supercolumn'] = <column_map>;
ColumnMapExpr columnMapExpr = getColumnMapExpr(valueNode);
ConstantOperand superColumnKey = new ConstantOperand(getColumn(columnFamilySpec, 0));
plan = new SetColumnMap(cfMetaData, rowKey, superColumnKey, columnMapExpr);
}
else
{
// Case: set table.super_cf['key'] = <super_column_map>;
logger_.assertLog(dimensionCnt == 0, "invalid dimensionCnt: " + dimensionCnt);
SuperColumnMapExpr superColumnMapExpr = getSuperColumnMapExpr(valueNode);
plan = new SetSuperColumnMap(cfMetaData, rowKey, superColumnMapExpr);
}
}
else // Standard column family
{
if (dimensionCnt == 1)
{
// Case: set table.standard_cf['key']['column'] = 'value'
OperandDef value = getSimpleExpr(valueNode);
ConstantOperand columnKey = new ConstantOperand(getColumn(columnFamilySpec, 0));
plan = new SetUniqueKey(cfMetaData, rowKey, columnKey, value);
}
else
{
// Case: set table.standard_cf['key'] = <column_map>;
logger_.assertLog(dimensionCnt == 0, "invalid dimensionCnt: " + dimensionCnt);
ColumnMapExpr columnMapExpr = getColumnMapExpr(valueNode);
plan = new SetColumnMap(cfMetaData, rowKey, columnMapExpr);
}
}
return plan;
}
private static void compileSelect(CommonTree ast) throws SemanticException
{
// stub; tbd.
}
private static void compileDelete(CommonTree ast) throws SemanticException
{
// stub; tbd.
}
}

View File

@ -0,0 +1,74 @@
/**
* 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.cql.driver;
import org.apache.cassandra.cql.compiler.common.*;
import org.apache.cassandra.cql.compiler.parse.*;
import org.apache.cassandra.cql.compiler.sem.*;
import org.apache.cassandra.cql.common.*;
import com.facebook.thrift.*;
import org.apache.cassandra.cql.common.CqlResult;
import org.apache.cassandra.cql.common.Plan;
import org.apache.cassandra.cql.compiler.common.CqlCompiler;
import org.apache.cassandra.cql.compiler.parse.ParseException;
import org.apache.cassandra.cql.compiler.sem.SemanticException;
import org.apache.cassandra.utils.LogUtil;
import org.apache.log4j.Logger;
// Server side driver class for CQL
public class CqlDriver
{
private final static Logger logger_ = Logger.getLogger(CqlDriver.class);
// Execute a CQL Statement
public static CqlResult executeQuery(String query) throws TException
{
CqlCompiler compiler = new CqlCompiler();
try
{
logger_.debug("Compiling CQL query ...");
Plan plan = compiler.compileQuery(query);
if (plan != null)
{
logger_.debug("Executing CQL query ...");
return plan.execute();
}
}
catch (Exception e)
{
CqlResult result = new CqlResult(null);
result.errorTxt = e.getMessage();
Class<? extends Exception> excpClass = e.getClass();
if ((excpClass != SemanticException.class)
&& (excpClass != ParseException.class)
&& (excpClass != RuntimeException.class))
{
result.errorTxt = "CQL Internal Error: " + result.errorTxt;
result.errorCode = 1; // failure
logger_.error(LogUtil.throwableToString(e));
}
return result;
}
return null;
}
}

View File

@ -0,0 +1,44 @@
/**
* 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.cql.execution;
/**
* List of error messages thrown by CQL's Execution Layer
**/
public enum RuntimeErrorMsg
{
// Error messages with String.format() style format specifiers
GENERIC_ERROR("CQL Execution Error"),
INTERNAL_ERROR("CQL Internal Error: %s"),
IMPLEMENTATION_RESTRICTION("Implementation Restriction: %s"),
NO_DATA_FOUND("No data found")
;
private String mesg;
RuntimeErrorMsg(String mesg)
{
this.mesg = mesg;
}
// Returns the formatted error message.
public String getMsg(Object... args)
{
// note: mesg itself might contain other format specifiers...
return String.format(mesg, args);
}
}

View File

@ -0,0 +1,133 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.db;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
/**
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
*/
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. */
if ( columnType == null || columnType.equals("Standard") )
return columnFactory_.get("Standard");
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 ICompactSerializer2<IColumn> createColumnSerializer();
}
class ColumnFactory extends AbstractColumnFactory
{
public IColumn createColumn(String name)
{
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 ICompactSerializer2<IColumn> createColumnSerializer()
{
return Column.serializer();
}
}
class SuperColumnFactory extends AbstractColumnFactory
{
static String[] getSuperColumnAndColumn(String cName)
{
StringTokenizer st = new StringTokenizer(cName, ":");
String[] values = new String[st.countTokens()];
int i = 0;
while ( st.hasMoreElements() )
{
values[i++] = (String)st.nextElement();
}
return values;
}
public IColumn createColumn(String name)
{
String[] values = SuperColumnFactory.getSuperColumnAndColumn(name);
if ( values.length == 0 || 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]);
if(values.length == 2)
{
IColumn subColumn = new Column(values[1]);
superColumn.addColumn(values[1], subColumn);
}
return superColumn;
}
public IColumn createColumn(String name, byte[] value)
{
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);
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

@ -0,0 +1,165 @@
/**
* 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.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.io.SSTable;
import org.apache.cassandra.utils.BloomFilter;
import org.apache.log4j.Logger;
import org.cliffc.high_scale_lib.NonBlockingHashMap;
/**
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
*/
public class BinaryMemtable implements MemtableMBean
{
private static Logger logger_ = Logger.getLogger( Memtable.class );
private int threshold_ = 512*1024*1024;
private AtomicInteger currentSize_ = new AtomicInteger(0);
/* Table and ColumnFamily name are used to determine the ColumnFamilyStore */
private String table_;
private String cfName_;
private boolean isFrozen_ = false;
private Map<String, byte[]> columnFamilies_ = new NonBlockingHashMap<String, byte[]>();
/* Lock and Condition for notifying new clients about Memtable switches */
Lock lock_ = new ReentrantLock();
Condition condition_;
BinaryMemtable(String table, String cfName) throws IOException
{
condition_ = lock_.newCondition();
table_ = table;
cfName_ = cfName;
}
public int getMemtableThreshold()
{
return currentSize_.get();
}
void resolveSize(int oldSize, int newSize)
{
currentSize_.addAndGet(newSize - oldSize);
}
boolean isThresholdViolated()
{
if (currentSize_.get() >= threshold_ || columnFamilies_.size() > 50000)
{
logger_.debug("CURRENT SIZE:" + currentSize_.get());
return true;
}
return false;
}
String getColumnFamily()
{
return cfName_;
}
/*
* This version is used by the external clients to put data into
* the memtable. This version will respect the threshold and flush
* the memtable to disk when the size exceeds the threshold.
*/
void put(String key, byte[] buffer) throws IOException
{
if (isThresholdViolated() )
{
lock_.lock();
try
{
ColumnFamilyStore cfStore = Table.open(table_).getColumnFamilyStore(cfName_);
if (!isFrozen_)
{
isFrozen_ = true;
BinaryMemtableManager.instance().submit(cfStore.getColumnFamilyName(), this);
cfStore.switchBinaryMemtable(key, buffer);
}
else
{
cfStore.applyBinary(key, buffer);
}
}
finally
{
lock_.unlock();
}
}
else
{
resolve(key, buffer);
}
}
private void resolve(String key, byte[] buffer)
{
columnFamilies_.put(key, buffer);
currentSize_.addAndGet(buffer.length + key.length());
}
/*
*
*/
void flush() throws IOException
{
if ( columnFamilies_.size() == 0 )
return;
ColumnFamilyStore cfStore = Table.open(table_).getColumnFamilyStore(cfName_);
String directory = DatabaseDescriptor.getDataFileLocation();
String filename = cfStore.getNextFileName();
/*
* Use the SSTable to write the contents of the TreeMap
* to disk.
*/
SSTable ssTable = new SSTable(directory, filename);
List<String> keys = new ArrayList<String>( columnFamilies_.keySet() );
Collections.sort(keys);
/* Use this BloomFilter to decide if a key exists in a SSTable */
BloomFilter bf = new BloomFilter(keys.size(), 8);
for ( String key : keys )
{
byte[] bytes = columnFamilies_.get(key);
if ( bytes.length > 0 )
{
/* Now write the key and value to disk */
ssTable.append(key, bytes);
bf.fill(key);
}
}
ssTable.close(bf);
cfStore.storeLocation( ssTable.getDataFileLocation(), bf );
columnFamilies_.clear();
}
}

Some files were not shown because too many files have changed in this diff Show More