Java tutorial
/* * Copyright (c) 2016 Rackspace. * * Licensed 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 com.rackspacecloud.blueflood.io.datastax; import com.datastax.driver.core.*; import com.google.common.collect.HashBasedTable; import com.google.common.collect.Table; import com.rackspacecloud.blueflood.io.CassandraModel; import com.rackspacecloud.blueflood.io.Instrumentation; import com.rackspacecloud.blueflood.rollup.Granularity; import com.rackspacecloud.blueflood.types.*; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.Long; import java.nio.ByteBuffer; import java.util.*; /** * This is an abstract class that collects the common behavior of * reading/writing preaggregated & basic numeric metrics objects. */ public abstract class DAbstractMetricIO { private static final Logger LOG = LoggerFactory.getLogger(DAbstractMetricIO.class); protected Session session; protected final DMetricsCFPreparedStatements metricsCFPreparedStatements; protected DAbstractMetricIO() { metricsCFPreparedStatements = DMetricsCFPreparedStatements.getInstance(); session = DatastaxIO.getSession(); } /** * Asynchronously insert a rolled up metric to the appropriate column family * for a particular granularity * * @param locator * @param collectionTime * @param rollup * @param granularity * @return */ public ResultSetFuture putAsync(Locator locator, long collectionTime, Rollup rollup, Granularity granularity, int ttl) { Session session = DatastaxIO.getSession(); // we use batch statement here in case sub classes // override the addRollupToBatch() and provide // multiple statements BatchStatement batch = new BatchStatement(); addRollupToBatch(batch, locator, rollup, collectionTime, granularity, ttl); Collection<Statement> statements = batch.getStatements(); if (statements.size() == 1) { Statement oneStatement = statements.iterator().next(); return session.executeAsync(oneStatement); } else { LOG.debug(String.format("Using BatchStatement for %d statements", statements.size())); return session.executeAsync(batch); } } public Statement createStatement(Locator locator, long collectionTime, Rollup rollup, Granularity granularity, int ttl) { final PreparedStatement statement; if (rollup.getRollupType() == RollupType.BF_BASIC) { // Strings and Booleans don't get rolled up. I'd like to verify // that none are passed in, but that would require a db access statement = metricsCFPreparedStatements.basicGranToInsertStatement.get(granularity); } else { statement = metricsCFPreparedStatements.preaggrGranToInsertStatement.get(granularity); } BoundStatement bound = statement.bind(locator.toString(), collectionTime, toByteBuffer(rollup), ttl); return bound; } /** * Fetch rollup objects for a {@link com.rackspacecloud.blueflood.types.Locator} * from the specified column family and range. * * @param locator * @param columnFamily * @param range * @return */ protected <T extends Object> Table<Locator, Long, T> getRollupsForLocator(final Locator locator, String columnFamily, Range range) { return getValuesForLocators(new ArrayList<Locator>() { { add(locator); } }, columnFamily, range); } /** * Fetch values for a list of {@link com.rackspacecloud.blueflood.types.Locator} * from the specified column family and range. * * This is a base behavior for most rollup types. IO subclasses can override * this behavior as they see fit. * * @param locators * @param columnFamily * @param range * @return */ protected <T extends Object> Table<Locator, Long, T> getValuesForLocators(final List<Locator> locators, String columnFamily, Range range) { Table<Locator, Long, T> locatorTimestampRollup = HashBasedTable.create(); Map<Locator, List<ResultSetFuture>> resultSetFuturesMap = selectForLocatorListAndRange(columnFamily, locators, range); for (Map.Entry<Locator, List<ResultSetFuture>> entry : resultSetFuturesMap.entrySet()) { Locator locator = entry.getKey(); List<ResultSetFuture> futures = entry.getValue(); Table<Locator, Long, T> result = toLocatorTimestampValue(futures, locator, columnFamily, range); locatorTimestampRollup.putAll(result); } return locatorTimestampRollup; } /** * Provides a way for the sub class to get a {@link java.nio.ByteBuffer} * representation of a certain value. * * @param value * @return */ protected abstract <T extends Object> ByteBuffer toByteBuffer(T value); /** * Provides a way for the sub class to construct the right Rollup * object from a {@link java.nio.ByteBuffer} * * @param byteBuffer * @return */ protected abstract <T extends Object> T fromByteBuffer(ByteBuffer byteBuffer); /** * Add a {@link com.datastax.driver.core.PreparedStatement} statement to the * {@link com.datastax.driver.core.BatchStatement} to insert this Rollup * object to metrics_preaggregated_{granularity} column family * * @param batch * @param locator * @param collectionTime * @param granularity * @param ttl */ protected void addRollupToBatch(BatchStatement batch, Locator locator, Rollup rollup, long collectionTime, Granularity granularity, int ttl) { Statement statement = createStatement(locator, collectionTime, rollup, granularity, ttl); batch.add(statement); } /** * Asynchronously execute select statements against the specified * column family for a specific list of * {@link com.rackspacecloud.blueflood.types.Locator} and * {@link com.rackspacecloud.blueflood.types.Range} * * @param locators * @param range * @return a map of Locator -> a list of ResultSetFuture */ protected Map<Locator, List<ResultSetFuture>> selectForLocatorListAndRange(String columnFamilyName, List<Locator> locators, Range range) { Map<Locator, List<ResultSetFuture>> locatorFuturesMap = new HashMap<Locator, List<ResultSetFuture>>(); for (Locator locator : locators) { List<ResultSetFuture> existing = locatorFuturesMap.get(locator); if (existing == null) { existing = new ArrayList<ResultSetFuture>(); locatorFuturesMap.put(locator, existing); } existing.addAll(selectForLocatorAndRange(columnFamilyName, locator, range)); } return locatorFuturesMap; } /** * Execute a select statement against the specified column family for a specific * {@link com.rackspacecloud.blueflood.types.Locator} and * {@link com.rackspacecloud.blueflood.types.Range} * * @param columnFamily the column family name to do select against * @param locator * @param range * @return */ protected List<ResultSetFuture> selectForLocatorAndRange(String columnFamily, Locator locator, Range range) { List<ResultSetFuture> resultsFutures = new ArrayList<ResultSetFuture>(); PreparedStatement statement = metricsCFPreparedStatements.cfNameToSelectStatement.get(columnFamily); resultsFutures .add(session.executeAsync(statement.bind(locator.toString(), range.getStart(), range.getStop()))); return resultsFutures; } /** * Give a {@link com.datastax.driver.core.ResultSetFuture}, get * the corresponding data from it and return it as a * Table of locator, long and rollup. */ public <T extends Object> Table<Locator, Long, T> toLocatorTimestampValue(List<ResultSetFuture> futures, Locator locator, String columnFamily, Range range) { Table<Locator, Long, T> locatorTimestampRollup = HashBasedTable.create(); for (ResultSetFuture future : futures) { try { List<Row> rows = future.getUninterruptibly().all(); // we only want to count the number of points we // get when we're querying the metrics_full if (StringUtils.isNotEmpty(columnFamily) && columnFamily.equals(CassandraModel.CF_METRICS_FULL_NAME)) { Instrumentation.getRawPointsIn5MinHistogram().update(rows.size()); } for (Row row : rows) { String key = row.getString(DMetricsCFPreparedStatements.KEY); Locator loc = Locator.createLocatorFromDbKey(key); Long hash = row.getLong(DMetricsCFPreparedStatements.COLUMN1); locatorTimestampRollup.put(loc, hash, (T) fromByteBuffer(row.getBytes(DMetricsCFPreparedStatements.VALUE))); } } catch (Exception ex) { Instrumentation.markReadError(); LOG.error(String.format("error reading metric for locator %s, column family '%s', range %s", locator, columnFamily, range.toString()), ex); } } return locatorTimestampRollup; } /** * Retrieves the {@link BoundStatement} for a particular metric and granularity. * Subclasses will implement this. * * @param metric * @param granularity * @return */ protected abstract BoundStatement getBoundStatementForMetric(IMetric metric, Granularity granularity); }