mirror of https://github.com/apache/cassandra
git-svn-id: https://svn.apache.org/repos/asf/incubator/cassandra/trunk@749218 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
commit
1f91e99223
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -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_;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
;
|
||||
|
|
@ -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
|
||||
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
;
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 */
|
||||
}
|
||||
|
||||
|
|
@ -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 */
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -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_;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -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();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -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() + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
|
@ -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_);
|
||||
}
|
||||
}
|
||||
|
|
@ -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_ + "'";
|
||||
}
|
||||
};
|
||||
|
|
@ -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
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -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 {};
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
};
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
|
@ -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_);
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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: ';';
|
||||
|
|
@ -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
|
|
@ -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: ';';
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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.
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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
Loading…
Reference in New Issue