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

com.hmsonline.cassandra.triggers.DistributedCommitLog Maven / Gradle / Ivy

Go to download

Cassandra Triggers is a lightweight mechanism to implement trigger-like functionality for Cassandra.

There is a newer version: 1.0.1
Show newest version
package com.hmsonline.cassandra.triggers;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;

import org.apache.cassandra.db.ColumnFamily;
import org.apache.cassandra.db.RowMutation;
import org.apache.cassandra.thrift.Column;
import org.apache.cassandra.thrift.ColumnOrSuperColumn;
import org.apache.cassandra.thrift.ColumnParent;
import org.apache.cassandra.thrift.ColumnPath;
import org.apache.cassandra.thrift.ConsistencyLevel;
import org.apache.cassandra.thrift.KeyRange;
import org.apache.cassandra.thrift.KeySlice;
import org.apache.cassandra.thrift.Mutation;
import org.apache.cassandra.thrift.SlicePredicate;
import org.apache.cassandra.thrift.SliceRange;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DistributedCommitLog extends CassandraStore {
    private static Logger logger = LoggerFactory.getLogger(DistributedCommitLog.class);

    public static final String KEYSPACE = "triggers";
    public static final String COLUMN_FAMILY = "CommitLog";
    public static final int MAX_NUMBER_COLUMNS = 1000;
    public static final int BATCH_SIZE = 50;
    public static final int IN_FUTURE = 1000 * 60;
    private static DistributedCommitLog instance = null;

    private static Timer triggerTimer = null;
    private static final long TRIGGER_FREQUENCY = 5000; // every X milliseconds
    private static final long MAX_LOG_ENTRY_AGE = 5000; // age of entry, at
                                                        // which time any node
                                                        // can process it.
    private String hostName = null;

    public DistributedCommitLog(String keyspace, String columnFamily) throws Exception {
        super(keyspace, columnFamily);
        logger.debug("Instantiated distributed commit log.");
        this.getHostName();
        triggerTimer = new Timer(true);
        triggerTimer.schedule(new TriggerTask(), 0, TRIGGER_FREQUENCY);
        logger.debug("Started Trigger Task thread.");
    }

    public static synchronized DistributedCommitLog getLog() throws Exception {
        if (instance == null) {
            instance = new DistributedCommitLog(KEYSPACE, COLUMN_FAMILY);
        }
        return instance;
    }

    public List writePending(ConsistencyLevel consistencyLevel, RowMutation rowMutation) throws Throwable {
        String keyspace = rowMutation.getTable();
        ByteBuffer rowKey = rowMutation.key();
        List entries = new ArrayList();
        for (Integer cfId : rowMutation.getColumnFamilyIds()) {
            ColumnFamily columnFamily = rowMutation.getColumnFamily(cfId);
            String hostName = this.getHostName();
            LogEntry entry = new LogEntry(keyspace, columnFamily, rowKey, consistencyLevel, hostName,
                    System.currentTimeMillis());
            entries.add(entry);
            writeLogEntry(entry);
        }
        return entries;
    }

    public List getPending() throws Throwable {
        SlicePredicate predicate = new SlicePredicate();
        SliceRange range = new SliceRange(ByteBufferUtil.bytes(""), ByteBufferUtil.bytes(""), false, MAX_NUMBER_COLUMNS);
        predicate.setSlice_range(range);

        KeyRange keyRange = new KeyRange(BATCH_SIZE);
        keyRange.setStart_key(ByteBufferUtil.bytes(""));
        keyRange.setEnd_key(ByteBufferUtil.EMPTY_BYTE_BUFFER);
        ColumnParent parent = new ColumnParent(COLUMN_FAMILY);
        List rows = getConnection(KEYSPACE).get_range_slices(parent, predicate, keyRange,
                ConsistencyLevel.ALL);
        List logEntries = new ArrayList();
        for (KeySlice keySlice : rows) {
            if (keySlice.columns.size() > 0) {
                LogEntry logEntry = new LogEntry();
                logEntry.setUuid(ByteBufferUtil.string(keySlice.key));
                for (ColumnOrSuperColumn cc : keySlice.columns) {
                    if (ByteBufferUtil.string(cc.column.name).equals("ks")) {
                        logEntry.setKeyspace(ByteBufferUtil.string(cc.column.value));
                    } else if (ByteBufferUtil.string(cc.column.name).equals("cf")) {
                        logEntry.setColumnFamily(ByteBufferUtil.string(cc.column.value));
                    } else if (ByteBufferUtil.string(cc.column.name).equals("row")) {
                        logEntry.setRowKey(cc.column.value);
                    } else if (ByteBufferUtil.string(cc.column.name).equals("status")) {
                        logEntry.setStatus(LogEntryStatus.valueOf(ByteBufferUtil.string(cc.column.value)));
                    } else if (ByteBufferUtil.string(cc.column.name).equals("timestamp")) {
                        logEntry.setTimestamp(Long.valueOf(ByteBufferUtil.string(cc.column.value)));
                    } else if (ByteBufferUtil.string(cc.column.name).equals("host")) {
                        logEntry.setHost(ByteBufferUtil.string(cc.column.value));
                    } else if (ConfigurationStore.getStore().shouldWriteColumns()){
                        ColumnOperation operation = new ColumnOperation();
                        operation.setName(cc.column.name);
                        operation.setOperationType(cc.column.value);
                    }
                }
                logEntries.add(logEntry);
            }
        }
        return logEntries;
    }

    public void writeLogEntry(LogEntry logEntry) throws Throwable {
        List slice = new ArrayList();
        slice.add(getMutation("ks", logEntry.getKeyspace()));
        slice.add(getMutation("cf", logEntry.getColumnFamily()));
        slice.add(getMutation("row", logEntry.getRowKey()));
        slice.add(getMutation("status", logEntry.getStatus().toString()));
        slice.add(getMutation("timestamp", Long.toString(logEntry.getTimestamp())));
        slice.add(getMutation("host", logEntry.getHost()));
        if (logEntry.hasErrors()) {
            for (String errorKey : logEntry.getErrors().keySet()) {
                slice.add(getMutation(errorKey, logEntry.getErrors().get(errorKey)));
            }
        }

        if (ConfigurationStore.getStore().shouldWriteColumns()) {
            for (ColumnOperation operation : logEntry.getOperations()) {
                if (operation.isDelete()) {
                    slice.add(getMutation(operation.getName(), OperationType.DELETE));
                } else {
                    slice.add(getMutation(operation.getName(), OperationType.UPDATE));
                }
            }
        }
        Map>> mutationMap = new HashMap>>();
        Map> cfMutations = new HashMap>();
        cfMutations.put(COLUMN_FAMILY, slice);

        ByteBuffer rowKey = ByteBufferUtil.bytes(logEntry.getUuid());
        mutationMap.put(rowKey, cfMutations);
        getConnection(KEYSPACE).batch_mutate(mutationMap, logEntry.getConsistencyLevel());
    }

    public void removeLogEntry(LogEntry logEntry) throws Throwable {
        long deleteTime = System.currentTimeMillis() * 1000;
        ColumnPath path = new ColumnPath(COLUMN_FAMILY);
        getConnection(KEYSPACE)
                .remove(ByteBufferUtil.bytes(logEntry.getUuid()), path, deleteTime, ConsistencyLevel.ALL);
    }

    public void errorLogEntry(LogEntry logEntry) throws Throwable {
        logEntry.setConsistencyLevel(ConsistencyLevel.ALL);
        DistributedCommitLog.getLog().writeLogEntry(logEntry);
    }

    // Utility Methods
    private Mutation getMutation(String name, String value) {
        return getMutation(name, ByteBufferUtil.bytes(value));
    }

    private Mutation getMutation(String name, ByteBuffer value) {
        return getMutation(ByteBufferUtil.bytes(name), value);
    }

    private Mutation getMutation(ByteBuffer name, OperationType value) {
        return getMutation(name, ByteBufferUtil.bytes(value.toString()));
    }

    private Mutation getMutation(ByteBuffer name, ByteBuffer value) {
        Column c = new Column();
        c.setName(name);
        c.setValue(value);
        c.setTimestamp(System.currentTimeMillis() * 1000);

        Mutation m = new Mutation();
        ColumnOrSuperColumn cc = new ColumnOrSuperColumn();
        cc.setColumn(c);
        m.setColumn_or_supercolumn(cc);
        return m;
    }

    public String getHostName() throws SocketException {
        if (hostName == null) {
            Enumeration interfaces = NetworkInterface.getNetworkInterfaces();
            {
                while (interfaces.hasMoreElements()) {
                    NetworkInterface nic = interfaces.nextElement();
                    Enumeration addresses = nic.getInetAddresses();
                    while (hostName == null && addresses.hasMoreElements()) {
                        InetAddress address = addresses.nextElement();
                        if (!address.isLoopbackAddress()) {
                            hostName = address.getHostName();
                            logger.debug("Host ID: " + hostName);
                        }
                    }
                }
            }
        }
        return this.hostName;
    }

    public boolean isMine(LogEntry logEntry) throws UnknownHostException, SocketException {
        return (logEntry.getHost().equals(this.getHostName()));
    }

    public boolean isOld(LogEntry logEntry) {
        long now = System.currentTimeMillis();
        long age = now - logEntry.getTimestamp();
        return (age > DistributedCommitLog.MAX_LOG_ENTRY_AGE);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy