
rapture.series.cassandra.AstyanaxSeriesConnection Maven / Gradle / Ivy
The newest version!
/**
* The MIT License (MIT)
*
* Copyright (c) 2011-2016 Incapture Technologies LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package rapture.series.cassandra;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import com.google.common.base.Function;
import com.google.common.base.Strings;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.netflix.astyanax.ColumnListMutation;
import com.netflix.astyanax.MutationBatch;
import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
import com.netflix.astyanax.connectionpool.exceptions.OperationException;
import com.netflix.astyanax.model.Column;
import com.netflix.astyanax.model.ColumnList;
import com.netflix.astyanax.util.RangeBuilder;
import rapture.cassandra.AstyanaxCassandraBase;
import rapture.common.RaptureFolderInfo;
import rapture.common.SeriesValue;
import rapture.common.exception.RaptureExceptionFactory;
import rapture.dsl.serfun.SeriesValueCodec;
import rapture.dsl.serfun.StringSeriesValue;
import rapture.series.children.ChildKeyUtil;
import rapture.series.children.ChildrenRepo;
public class AstyanaxSeriesConnection extends AstyanaxCassandraBase {
private static final String DIRECTORY_KEY = "..directory";
private final int OVERFLOW_LIMIT;
private Cache keyCache = CacheBuilder.newBuilder().expireAfterAccess(3, TimeUnit.SECONDS).build();
private final ChildrenRepo childrenRepo;
public AstyanaxSeriesConnection(String instance, Map config, int overflowLimit) {
super(instance, config);
OVERFLOW_LIMIT = overflowLimit;
this.childrenRepo = new ChildrenRepo() {
@Override
public List getPoints(String key) {
try {
return AstyanaxSeriesConnection.this.getPoints(key);
} catch (IOException e) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, messageCatalog.getMessage("DbCommsError"), e);
}
}
@Override
public boolean addPoint(String key, SeriesValue value) {
AstyanaxSeriesConnection.this.addPoint(key, value);
return true;
}
@Override
public boolean dropPoints(String key, List points) {
return AstyanaxSeriesConnection.this.dropPoints(key, points);
}
@Override
public boolean dropRow(String key) {
return AstyanaxSeriesConnection.this.dropAllPoints(key);
}
};
}
public void drop() throws OperationException, ConnectionException {
keyCache.invalidateAll();
keyspace.truncateColumnFamily(columnFamily);
}
private SeriesValue makeSeriesValueFromByteArray(String column, byte[] array) throws IOException {
return SeriesValueCodec.decode(column, array);
}
public void addPoint(String key, SeriesValue value) {
registerKey(key);
try {
keyspace.prepareColumnMutation(columnFamily, key, value.getColumn()).putValue(SeriesValueCodec.encodeValue(value), null).execute();
} catch (ConnectionException | UnsupportedEncodingException ce) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, messageCatalog.getMessage("DbCommsError"), ce);
}
}
public Boolean dropPoints(String key, List columns) {
MutationBatch m = keyspace.prepareMutationBatch();
for (String columnName : columns) {
m.withRow(columnFamily, key).deleteColumn(columnName);
}
try {
m.execute();
} catch (ConnectionException ce) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, messageCatalog.getMessage("DbCommsError"), ce);
}
return true;
}
public boolean dropAllPoints(String key) {
unregisterKey(key);
MutationBatch m = keyspace.prepareMutationBatch();
m.withRow(columnFamily, key).delete();
try {
m.execute();
} catch (ConnectionException ce) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, messageCatalog.getMessage("DbCommsError"), ce);
}
return true;
}
public List getPoints(String key) throws IOException {
String startColumn = "";
return getPointsAfter(key, startColumn, Integer.MAX_VALUE, false);
}
public List getPointsAfter(String key, String startColumn, int maxNumber, boolean reverse) throws IOException {
return getPointsAfter(key, startColumn, "", maxNumber, reverse);
}
public List getPointsAfter(String key, String startColumn, String endColumn, int maxNumber, boolean reverse) throws IOException {
List ret = new ArrayList();
int limit = (maxNumber > OVERFLOW_LIMIT) ? OVERFLOW_LIMIT + 1 : maxNumber;
ColumnList result;
try {
result = keyspace.prepareQuery(columnFamily).getKey(key)
.withColumnRange(new RangeBuilder().setStart(startColumn).setEnd(endColumn).setLimit(limit).setReversed(reverse).build()).execute()
.getResult();
} catch (ConnectionException ce) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, messageCatalog.getMessage("DbCommsError"), ce);
}
if (result.size() > OVERFLOW_LIMIT) {
throw RaptureExceptionFactory.create(messageCatalog.getMessage("SmallerPages", ""+OVERFLOW_LIMIT));
}
for (Column column : result) {
ret.add(makeSeriesValue(column));
}
return ret;
}
public List getSeriesLike(String keyPrefix) throws IOException {
if (Strings.isNullOrEmpty(keyPrefix)) {
List listings = getPoints(DIRECTORY_KEY);
return Lists.transform(listings, colFunc);
} else {
int lastCharValue = keyPrefix.charAt(keyPrefix.length() - 1) + 1;
String endPrefix = keyPrefix.substring(0, keyPrefix.length() - 1) + ((char) lastCharValue);
List listings = getPointsAfter(DIRECTORY_KEY, keyPrefix, endPrefix, Integer.MAX_VALUE, false);
List result = Lists.transform(listings, colFunc);
if (result.size() > 0 && endPrefix.equals(result.get(result.size() - 1))) {
result.subList(result.size() - 1, result.size()).clear();
}
return result;
}
}
private static Function colFunc = new Function() {
@Override
public String apply(SeriesValue v) {
return v.getColumn();
}
};
public void addPoint(String key, List values) {
boolean nullKey = false;
try {
registerKey(key);
MutationBatch m = keyspace.prepareMutationBatch();
ColumnListMutation mut = m.withRow(columnFamily, key);
for (SeriesValue value : values) {
if (value.getColumn() == null) nullKey = true;
else mut.putColumn(value.getColumn(), SeriesValueCodec.encodeValue(value), null);
}
m.execute();
} catch (ConnectionException ce) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, messageCatalog.getMessage("DbCommsError"), ce);
} catch (UnsupportedEncodingException e) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, messageCatalog.getMessage("BadSeriesValue"), e);
}
if (nullKey) throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_BAD_REQUEST, messageCatalog.getMessage("BadKey"));
}
private Callable FALSE_CALL = new Callable() {
@Override
public Boolean call() {
return false;
}
};
void registerKey(String key) {
if (DIRECTORY_KEY.equals(key) || ChildKeyUtil.isRowKey(key)) {
return;
} else try {
if (keyCache.get(key, FALSE_CALL) == false) {
addPoint(DIRECTORY_KEY, new StringSeriesValue(".", key));
childrenRepo.registerParentage(key);
keyCache.put(key, true);
}
} catch (ExecutionException e) {
// this should never ever happen
throw RaptureExceptionFactory.create("Severe: the line 'return false;' just failed");
}
}
void unregisterKey(String key) {
unregisterKey(key, false);
}
boolean unregisterKey(String key, boolean isFolder) {
boolean ret = false;
if (DIRECTORY_KEY.equals(key)) {
return ret;
}
dropPoints(DIRECTORY_KEY, ImmutableList.of(key));
if (isFolder) ret = childrenRepo.dropFolderEntry(key);
else ret = childrenRepo.dropFileEntry(key);
keyCache.invalidate(key);
return ret;
}
private final SeriesValue makeSeriesValue(Column column) throws IOException {
return makeSeriesValueFromByteArray(column.getName(), column.getByteArrayValue());
}
public List getChildren(String folderName) {
return childrenRepo.getChildren(folderName);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy