All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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