use of org.apache.accumulo.core.client.ConditionalWriterConfig in project incubator-rya by apache.
the class PcjTables method updateCardinality.
/**
* Update the cardinality of a PCJ by a {@code delta}.
*
* @param accumuloConn - A connection to the Accumulo that hosts the PCJ table. (not null)
* @param pcjTableName - The name of the PCJ table that will have its cardinality updated. (not null)
* @param delta - How much the cardinality will change.
* @throws PCJStorageException The cardinality could not be updated.
*/
private void updateCardinality(final Connector accumuloConn, final String pcjTableName, final long delta) throws PCJStorageException {
checkNotNull(accumuloConn);
checkNotNull(pcjTableName);
ConditionalWriter conditionalWriter = null;
try {
conditionalWriter = accumuloConn.createConditionalWriter(pcjTableName, new ConditionalWriterConfig());
boolean updated = false;
while (!updated) {
// Write the conditional update request to Accumulo.
final long cardinality = getPcjMetadata(accumuloConn, pcjTableName).getCardinality();
final ConditionalMutation mutation = makeUpdateCardinalityMutation(cardinality, delta);
final ConditionalWriter.Result result = conditionalWriter.write(mutation);
// Interpret the result.
switch(result.getStatus()) {
case ACCEPTED:
updated = true;
break;
case REJECTED:
break;
case UNKNOWN:
// We do not know if the mutation succeeded. At best, we
// can hope the metadata hasn't been updated
// since we originally fetched it and try again.
// Otherwise, continue forwards as if it worked. It's
// okay if this number is slightly off.
final long newCardinality = getPcjMetadata(accumuloConn, pcjTableName).getCardinality();
if (newCardinality != cardinality) {
updated = true;
}
break;
case VIOLATED:
throw new PCJStorageException("The cardinality could not be updated because the commit violated a table constraint.");
case INVISIBLE_VISIBILITY:
throw new PCJStorageException("The condition contains a visibility the updater can not satisfy.");
}
}
} catch (AccumuloException | AccumuloSecurityException | TableNotFoundException e) {
throw new PCJStorageException("Could not update the cardinality value of the PCJ Table named: " + pcjTableName, e);
} finally {
if (conditionalWriter != null) {
conditionalWriter.close();
}
}
}
use of org.apache.accumulo.core.client.ConditionalWriterConfig in project accumulo-examples by apache.
the class ARS method cancel.
public void cancel(String what, String when, String who) throws Exception {
String row = what + ":" + when;
// its important to use an isolated scanner so that only whole mutations are seen
try (ConditionalWriter cwriter = conn.createConditionalWriter(rTable, new ConditionalWriterConfig());
Scanner scanner = new IsolatedScanner(conn.createScanner(rTable, Authorizations.EMPTY))) {
while (true) {
scanner.setRange(new Range(row));
int seq = -1;
String reservation = null;
for (Entry<Key, Value> entry : scanner) {
String cf = entry.getKey().getColumnFamilyData().toString();
String cq = entry.getKey().getColumnQualifierData().toString();
String val = entry.getValue().toString();
if (cf.equals("tx") && cq.equals("seq")) {
seq = Integer.parseInt(val);
} else if (cf.equals("res") && val.equals(who)) {
reservation = cq;
}
}
if (reservation != null) {
ConditionalMutation update = new ConditionalMutation(row, new Condition("tx", "seq").setValue(seq + ""));
update.putDelete("res", reservation);
update.put("tx", "seq", (seq + 1) + "");
Status status = cwriter.write(update).getStatus();
switch(status) {
case ACCEPTED:
// successfully canceled reservation
return;
case REJECTED:
case UNKNOWN:
// EXCERCISE exponential back-off could be used here
break;
default:
throw new RuntimeException("Unexpected status " + status);
}
} else {
// not reserved, nothing to do
break;
}
}
}
}
use of org.apache.accumulo.core.client.ConditionalWriterConfig in project accumulo-examples by apache.
the class ARS method reserve.
public ReservationResult reserve(String what, String when, String who) throws Exception {
String row = what + ":" + when;
// EXCERCISE This code assumes there is no reservation and tries to create one. If a reservation exist then the update will fail. This is a good strategy
// when it is expected there are usually no reservations. Could modify the code to scan first.
// The following mutation requires that the column tx:seq does not exist and will fail if it does.
ConditionalMutation update = new ConditionalMutation(row, new Condition("tx", "seq"));
update.put("tx", "seq", "0");
update.put("res", String.format("%04d", 0), who);
ReservationResult result = ReservationResult.RESERVED;
// it is important to use an isolated scanner so that only whole mutations are seen
try (ConditionalWriter cwriter = conn.createConditionalWriter(rTable, new ConditionalWriterConfig());
Scanner scanner = new IsolatedScanner(conn.createScanner(rTable, Authorizations.EMPTY))) {
while (true) {
Status status = cwriter.write(update).getStatus();
switch(status) {
case ACCEPTED:
return result;
case REJECTED:
case UNKNOWN:
// read the row and decide what to do
break;
default:
throw new RuntimeException("Unexpected status " + status);
}
// EXCERCISE in the case of many threads trying to reserve a slot, this approach of immediately retrying is inefficient. Exponential back-off is good
// general solution to solve contention problems like this. However in this particular case, exponential back-off could penalize the earliest threads
// that attempted to make a reservation by putting them later in the list. A more complex solution could involve having independent sub-queues within
// the row that approximately maintain arrival order and use exponential back off to fairly merge the sub-queues into the main queue.
scanner.setRange(new Range(row));
int seq = -1;
int maxReservation = -1;
for (Entry<Key, Value> entry : scanner) {
String cf = entry.getKey().getColumnFamilyData().toString();
String cq = entry.getKey().getColumnQualifierData().toString();
String val = entry.getValue().toString();
if (cf.equals("tx") && cq.equals("seq")) {
seq = Integer.parseInt(val);
} else if (cf.equals("res")) {
// data differently in Accumulo so that finding the reserver could be done quickly.
if (val.equals(who))
if (maxReservation == -1)
// already have the first reservation
return ReservationResult.RESERVED;
else
// already on wait list
return ReservationResult.WAIT_LISTED;
// EXCERCISE the way this code finds the max reservation is very inefficient.... it would be better if it did not have to scan the entire row.
// One possibility is to just use the sequence number. Could also consider sorting the data in another way and/or using an iterator.
maxReservation = Integer.parseInt(cq);
}
}
Condition condition = new Condition("tx", "seq");
if (seq >= 0)
// only expect a seq # if one was seen
condition.setValue(seq + "");
update = new ConditionalMutation(row, condition);
update.put("tx", "seq", (seq + 1) + "");
update.put("res", String.format("%04d", maxReservation + 1), who);
// EXCERCISE if set capacity is implemented, then result should take capacity into account
if (maxReservation == -1)
// if successful, will be first reservation
result = ReservationResult.RESERVED;
else
result = ReservationResult.WAIT_LISTED;
}
}
}
use of org.apache.accumulo.core.client.ConditionalWriterConfig in project incubator-rya by apache.
the class AccumuloRyaInstanceDetailsRepository method update.
@Override
public void update(final RyaDetails oldDetails, final RyaDetails newDetails) throws NotInitializedException, ConcurrentUpdateException, RyaDetailsRepositoryException {
// Preconditions.
requireNonNull(oldDetails);
requireNonNull(newDetails);
if (!newDetails.getRyaInstanceName().equals(instanceName)) {
throw new RyaDetailsRepositoryException("The instance name that was in the provided 'newDetails' does not match " + "the instance name that this repository is connected to. Make sure you're connected to the" + "correct Rya instance.");
}
if (!isInitialized()) {
throw new NotInitializedException("Could not update the details for the Rya instanced named '" + instanceName + "' because it has not been initialized yet.");
}
// Use a conditional writer so that we can detect when the old details
// are no longer the currently stored ones.
ConditionalWriter writer = null;
try {
// Setup the condition that ensures the details have not changed since the edits were made.
final byte[] oldDetailsBytes = serializer.serialize(oldDetails);
final Condition condition = new Condition(COL_FAMILY, COL_QUALIFIER);
condition.setValue(oldDetailsBytes);
// Create the mutation that only performs the update if the details haven't changed.
final ConditionalMutation mutation = new ConditionalMutation(ROW_ID);
mutation.addCondition(condition);
final byte[] newDetailsBytes = serializer.serialize(newDetails);
mutation.put(COL_FAMILY, COL_QUALIFIER, new Value(newDetailsBytes));
// Do the write.
writer = connector.createConditionalWriter(detailsTableName, new ConditionalWriterConfig());
final Result result = writer.write(mutation);
switch(result.getStatus()) {
case REJECTED:
case VIOLATED:
throw new ConcurrentUpdateException("Could not update the details for the Rya instance named '" + instanceName + "' because the old value is out of date.");
case UNKNOWN:
case INVISIBLE_VISIBILITY:
throw new RyaDetailsRepositoryException("Could not update the details for the Rya instance named '" + instanceName + "'.");
}
} catch (final TableNotFoundException | AccumuloException | AccumuloSecurityException e) {
throw new RyaDetailsRepositoryException("Could not update the details for the Rya instance named '" + instanceName + "'.");
} finally {
if (writer != null) {
writer.close();
}
}
}
use of org.apache.accumulo.core.client.ConditionalWriterConfig in project accumulo by apache.
the class ConditionalWriterIT method testConstraints.
@Test
public void testConstraints() throws Exception {
// ensure constraint violations are properly reported
Connector conn = getConnector();
String tableName = getUniqueNames(1)[0];
conn.tableOperations().create(tableName);
conn.tableOperations().addConstraint(tableName, AlphaNumKeyConstraint.class.getName());
conn.tableOperations().clone(tableName, tableName + "_clone", true, new HashMap<>(), new HashSet<>());
try (ConditionalWriter cw = conn.createConditionalWriter(tableName + "_clone", new ConditionalWriterConfig());
Scanner scanner = conn.createScanner(tableName + "_clone", new Authorizations())) {
ConditionalMutation cm0 = new ConditionalMutation("99006+", new Condition("tx", "seq"));
cm0.put("tx", "seq", "1");
Assert.assertEquals(Status.VIOLATED, cw.write(cm0).getStatus());
Assert.assertFalse("Should find no results in the table is mutation result was violated", scanner.iterator().hasNext());
ConditionalMutation cm1 = new ConditionalMutation("99006", new Condition("tx", "seq"));
cm1.put("tx", "seq", "1");
Assert.assertEquals(Status.ACCEPTED, cw.write(cm1).getStatus());
Assert.assertTrue("Accepted result should be returned when reading table", scanner.iterator().hasNext());
}
}
Aggregations