Skip to content
This repository was archived by the owner on Mar 30, 2021. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<cassandra-unit.version>2.0.2.3-lng1</cassandra-unit.version>
<cucumber.version>1.2.2</cucumber.version>
<easymock.version>3.3.1</easymock.version>
<guava.version>16.0</guava.version>
<guava.version>16.0.1</guava.version>
<guice.version>3.0</guice.version>
<httpclient.version>4.4</httpclient.version>
<jackson.version>2.3.2</jackson.version>
Expand Down
7 changes: 6 additions & 1 deletion push-dao-cassandra/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,12 @@
<dependency>
<groupId>com.datastax.cassandra</groupId>
<artifactId>cassandra-driver-core</artifactId>
<version>2.1.4</version>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>com.datastax.cassandra</groupId>
<artifactId>cassandra-driver-mapping</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ protected CassandraService(
}

public void errorIfNoTable(String tableName) {
Where query = select("columnfamily_name").from("System", "schema_columnfamilies")
Where query = select("table_name").from("system_schema", "tables")
.where(eq("keyspace_name", configuration.keyspace()))
.and(eq("columnfamily_name", tableName));
.and(eq("table_name", tableName));
ResultSet resultSet = sessionProvider.get().execute(query);
if (resultSet.isExhausted()) {
throw new NoTableException(tableName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,40 +31,56 @@
* ***** END LICENSE BLOCK ***** */
package org.obm.push.cassandra;

import org.obm.push.configuration.CassandraConfiguration;

import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.ConsistencyLevel;
import com.datastax.driver.core.Statement;
import com.datastax.driver.core.WriteType;
import com.datastax.driver.core.exceptions.DriverException;
import com.datastax.driver.core.policies.RetryPolicy;
import org.obm.push.configuration.CassandraConfiguration;

public class RetryNTimesRetryPolicy implements RetryPolicy {

private final int maxNbRetry;
private final int maxNbRetry;

public RetryNTimesRetryPolicy(CassandraConfiguration cassandraConfiguration) {
this.maxNbRetry = cassandraConfiguration.maxRetries();
}

@Override
public RetryDecision onReadTimeout(Statement statement, ConsistencyLevel cl, int requiredResponses, int receivedResponses, boolean dataRetrieved, int nbRetry) {
return retry(cl, nbRetry);
}

@Override
public RetryDecision onWriteTimeout(Statement statement, ConsistencyLevel cl, WriteType writeType, int requiredAcks, int receivedAcks, int nbRetry) {
return retry(cl, nbRetry);
}

@Override
public RetryDecision onUnavailable(Statement statement, ConsistencyLevel cl, int requiredReplica, int aliveReplica, int nbRetry) {
return retry(cl, nbRetry);
}

@Override
public RetryDecision onRequestError(Statement statement, ConsistencyLevel consistencyLevel, DriverException e, int nbRetry) {
return retry(consistencyLevel, nbRetry);
}

public RetryNTimesRetryPolicy(CassandraConfiguration cassandraConfiguration) {
this.maxNbRetry = cassandraConfiguration.maxRetries();
}
@Override
public void init(Cluster cluster) {

@Override
public RetryDecision onReadTimeout(Statement statement, ConsistencyLevel cl, int requiredResponses, int receivedResponses, boolean dataRetrieved, int nbRetry) {
return retry(cl, nbRetry);
}
}

@Override
public RetryDecision onWriteTimeout(Statement statement, ConsistencyLevel cl, WriteType writeType, int requiredAcks, int receivedAcks, int nbRetry) {
return retry(cl, nbRetry);
}
@Override
public void close() {

@Override
public RetryDecision onUnavailable(Statement statement, ConsistencyLevel cl, int requiredReplica, int aliveReplica, int nbRetry) {
return retry(cl, nbRetry);
}
}

private RetryDecision retry(ConsistencyLevel cl, int nbRetry) {
if (nbRetry >= maxNbRetry) {
return RetryDecision.rethrow();
}
return RetryDecision.retry(cl);
}
private RetryDecision retry(ConsistencyLevel cl, int nbRetry) {
if (nbRetry >= maxNbRetry) {
return RetryDecision.rethrow();
}
return RetryDecision.retry(cl);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,45 +31,61 @@
* ***** END LICENSE BLOCK ***** */
package org.obm.push.cassandra;

import org.obm.push.configuration.CassandraConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.ConsistencyLevel;
import com.datastax.driver.core.Statement;
import com.datastax.driver.core.WriteType;
import com.datastax.driver.core.exceptions.DriverException;
import com.datastax.driver.core.policies.DowngradingConsistencyRetryPolicy;
import com.datastax.driver.core.policies.RetryPolicy;
import org.obm.push.configuration.CassandraConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RetryOrCLDowngradeRetryPolicy implements RetryPolicy {

private static final Logger LOGGER = LoggerFactory.getLogger(RetryOrCLDowngradeRetryPolicy.class);

private final int maxNbRetry;
private final RetryPolicy readAndWriteRetryPolicy;
private static final Logger LOGGER = LoggerFactory.getLogger(RetryOrCLDowngradeRetryPolicy.class);

private final int maxNbRetry;
private final RetryPolicy readAndWriteRetryPolicy;

public RetryOrCLDowngradeRetryPolicy(CassandraConfiguration cassandraConfiguration, RetryPolicy readAndWriteRetryPolicy) {
this.maxNbRetry = cassandraConfiguration.maxRetries();
this.readAndWriteRetryPolicy = readAndWriteRetryPolicy;
}

@Override
public RetryDecision onReadTimeout(Statement statement, ConsistencyLevel cl, int requiredResponses, int receivedResponses, boolean dataRetrieved, int nbRetry) {
return readAndWriteRetryPolicy.onReadTimeout(statement, cl, requiredResponses, receivedResponses, dataRetrieved, nbRetry);
}

@Override
public RetryDecision onWriteTimeout(Statement statement, ConsistencyLevel cl, WriteType writeType, int requiredAcks, int receivedAcks, int nbRetry) {
return readAndWriteRetryPolicy.onWriteTimeout(statement, cl, writeType, requiredAcks, receivedAcks, nbRetry);
}

@Override
public RetryDecision onUnavailable(Statement statement, ConsistencyLevel cl, int requiredReplica, int aliveReplica, int nbRetry) {
if (nbRetry >= maxNbRetry) {
return RetryDecision.rethrow();
}
LOGGER.warn("Opush is downgrading the consistency-level of a Cassandra request as it cannot reach enough replicas to get the QUORUM. " +
"A 'nodetool repair' might be done on each node when your cluster gets back to a healthy state. Read http://docs.obm.org/opush/ for more information");
return DowngradingConsistencyRetryPolicy.INSTANCE.onUnavailable(statement, cl, requiredReplica, aliveReplica, 0);
}

@Override
public RetryDecision onRequestError(Statement statement, ConsistencyLevel cl, DriverException e, int nbRetry) {
return readAndWriteRetryPolicy.onRequestError(statement, cl, e, nbRetry);
}

public RetryOrCLDowngradeRetryPolicy(CassandraConfiguration cassandraConfiguration, RetryPolicy readAndWriteRetryPolicy) {
this.maxNbRetry = cassandraConfiguration.maxRetries();
this.readAndWriteRetryPolicy = readAndWriteRetryPolicy;
}
@Override
public void init(Cluster cluster) {

@Override
public RetryDecision onReadTimeout(Statement statement, ConsistencyLevel cl, int requiredResponses, int receivedResponses, boolean dataRetrieved, int nbRetry) {
return readAndWriteRetryPolicy.onReadTimeout(statement, cl, requiredResponses, receivedResponses, dataRetrieved, nbRetry);
}
}

@Override
public RetryDecision onWriteTimeout(Statement statement, ConsistencyLevel cl, WriteType writeType, int requiredAcks, int receivedAcks, int nbRetry) {
return readAndWriteRetryPolicy.onWriteTimeout(statement, cl, writeType, requiredAcks, receivedAcks, nbRetry);
}
@Override
public void close() {

@Override
public RetryDecision onUnavailable(Statement statement, ConsistencyLevel cl, int requiredReplica, int aliveReplica, int nbRetry) {
if (nbRetry >= maxNbRetry) {
return RetryDecision.rethrow();
}
LOGGER.warn("Opush is downgrading the consistency-level of a Cassandra request as it cannot reach enough replicas to get the QUORUM. " +
"A 'nodetool repair' might be done on each node when your cluster gets back to a healthy state. Read http://docs.obm.org/opush/ for more information");
return DowngradingConsistencyRetryPolicy.INSTANCE.onUnavailable(statement, cl, requiredReplica, aliveReplica, 0);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,17 @@
* ***** END LICENSE BLOCK ***** */
package org.obm.push.cassandra.dao;

import static com.datastax.driver.core.querybuilder.QueryBuilder.desc;
import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
import static com.datastax.driver.core.querybuilder.QueryBuilder.insertInto;
import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
import static org.obm.push.cassandra.dao.CassandraStructure.Schema.TABLE;
import static org.obm.push.cassandra.dao.CassandraStructure.Schema.Columns.DATE;
import static org.obm.push.cassandra.dao.CassandraStructure.Schema.Columns.ID;
import static org.obm.push.cassandra.dao.CassandraStructure.Schema.Columns.VERSION;

import java.util.Iterator;
import java.util.List;

import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.querybuilder.Insert;
import com.datastax.driver.core.querybuilder.Select;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import org.obm.breakdownduration.bean.Watch;
import org.obm.push.bean.BreakdownGroups;
import org.obm.push.bean.migration.NoVersionException;
Expand All @@ -55,87 +54,88 @@
import org.obm.sync.date.DateProvider;
import org.slf4j.Logger;

import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.querybuilder.Insert;
import com.datastax.driver.core.querybuilder.Select;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import java.util.Iterator;
import java.util.List;

import static com.datastax.driver.core.querybuilder.QueryBuilder.desc;
import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
import static com.datastax.driver.core.querybuilder.QueryBuilder.insertInto;
import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
import static org.obm.push.cassandra.dao.CassandraStructure.Schema.Columns.DATE;
import static org.obm.push.cassandra.dao.CassandraStructure.Schema.Columns.ID;
import static org.obm.push.cassandra.dao.CassandraStructure.Schema.Columns.VERSION;
import static org.obm.push.cassandra.dao.CassandraStructure.Schema.TABLE;

@Singleton
@Watch(BreakdownGroups.CASSANDRA)
public class CassandraSchemaDao extends AbstractCassandraDao implements CassandraDao, SchemaDao {

private static final int SINGLE_ROW_ID = 1;
private static final int ONE_RESULT = 1;

private final CassandraService cassandraService;
private final DateProvider dateProvider;
private static final int SINGLE_ROW_ID = 1;
private static final int ONE_RESULT = 1;

private final CassandraService cassandraService;
private final DateProvider dateProvider;

@Inject
@VisibleForTesting
public CassandraSchemaDao(Provider<Session> sessionProvider, JSONService jsonService,
@Named(LoggerModule.CASSANDRA) Logger logger,
CassandraService cassandraService,
DateProvider dateProvider) {
super(sessionProvider, jsonService, logger);
this.cassandraService = cassandraService;
this.dateProvider = dateProvider;
}

@Override
public VersionUpdate getCurrentVersion() {
cassandraService.errorIfNoTable(TABLE.get());
Select query = select(VERSION, DATE).from(TABLE.get())
.where(eq(ID, SINGLE_ROW_ID))
.limit(ONE_RESULT)
.orderBy(desc(VERSION));
logger.debug("perform getCurrentVersion request {}", query.getQueryString());

ResultSet resultSet = getSession().execute(query);
if (resultSet.isExhausted()) {
throw new NoVersionException();
}

@Inject
@VisibleForTesting public CassandraSchemaDao(Provider<Session> sessionProvider, JSONService jsonService,
@Named(LoggerModule.CASSANDRA)Logger logger,
CassandraService cassandraService,
DateProvider dateProvider) {
super(sessionProvider, jsonService, logger);
this.cassandraService = cassandraService;
this.dateProvider = dateProvider;
}
VersionUpdate schemaUpdate = rowToSchemaUpdate(resultSet.one());
logger.debug("Current version found {}", schemaUpdate);
return schemaUpdate;
}

@Override
public VersionUpdate getCurrentVersion() {
cassandraService.errorIfNoTable(TABLE.get());
Select query = select(VERSION, DATE).from(TABLE.get())
.where(eq(ID, SINGLE_ROW_ID))
.limit(ONE_RESULT)
.orderBy(desc(VERSION));
logger.debug("perform getCurrentVersion request {}", query.getQueryString());

ResultSet resultSet = getSession().execute(query);
if (resultSet.isExhausted()) {
throw new NoVersionException();
}

VersionUpdate schemaUpdate = rowToSchemaUpdate(resultSet.one());
logger.debug("Current version found {}", schemaUpdate);
return schemaUpdate;
}
@Override
public List<VersionUpdate> getHistory() {
cassandraService.errorIfNoTable(TABLE.get());
Select query = select(VERSION, DATE).from(TABLE.get())
.where(eq(ID, SINGLE_ROW_ID))
.orderBy(desc(VERSION));
logger.debug("perform getHistory request {}", query.getQueryString());

@Override
public List<VersionUpdate> getHistory() {
cassandraService.errorIfNoTable(TABLE.get());
Select query = select(VERSION, DATE).from(TABLE.get())
.where(eq(ID, SINGLE_ROW_ID))
.orderBy(desc(VERSION));
logger.debug("perform getHistory request {}", query.getQueryString());

ImmutableList.Builder<VersionUpdate> historyBuilder = ImmutableList.builder();
Iterator<Row> results = getSession().execute(query).iterator();
while (results.hasNext()) {
historyBuilder.add(rowToSchemaUpdate(results.next()));
}
return historyBuilder.build();
}
ImmutableList.Builder<VersionUpdate> historyBuilder = ImmutableList.builder();
Iterator<Row> results = getSession().execute(query).iterator();
while (results.hasNext()) {
historyBuilder.add(rowToSchemaUpdate(results.next()));
}
return historyBuilder.build();
}

@Override
public void updateVersion(Version target) {
cassandraService.errorIfNoTable(TABLE.get());
Insert query = insertInto(TABLE.get())
.value(ID, SINGLE_ROW_ID)
.value(VERSION, target.get())
.value(DATE, dateProvider.getDate());
logger.debug("perform updateVersion request {}", query.getQueryString());
getSession().execute(query);
}
@Override
public void updateVersion(Version target) {
cassandraService.errorIfNoTable(TABLE.get());
Insert query = insertInto(TABLE.get())
.value(ID, SINGLE_ROW_ID)
.value(VERSION, target.get())
.value(DATE, dateProvider.getDate());
logger.debug("perform updateVersion request {}", query.getQueryString());
getSession().execute(query);
}

private VersionUpdate rowToSchemaUpdate(Row schemaUpdateRow) {
return VersionUpdate
.version(Version.of(schemaUpdateRow.getInt(VERSION)))
.date(schemaUpdateRow.getDate(DATE));
}
private VersionUpdate rowToSchemaUpdate(Row schemaUpdateRow) {
return VersionUpdate
.version(Version.of(schemaUpdateRow.getInt(VERSION)))
.date(schemaUpdateRow.getTimestamp(DATE));
}
}
Loading