use of com.cinchapi.concourse.server.storage.AtomicOperation in project concourse by cinchapi.
the class Stores method serialSelect.
/**
* Select the values stored for {@code key} in {@code record} at
* {@code timestamp} from the {@code store}.
* <p>
* If the {@code key} is primitive, the store retrieval is usually a simple
* {@link Store#select(long) select}. However, if the key is a navigation
* key, this method will process it via
* {@link Operations#traverseKeyRecordOptionalAtomic(String, long, long, AtomicOperation)}
* if the {@code store} is an {@link AtomicOperation} or
* {@link AtomicSupport supports} starting one.
* </p>
*
* @param store
* @param key
* @param record
* @param timestamp
*
* @return the values stored for {@code key} in {@code record} at
* {@code timestamp} according to the {@code store}
*/
protected static Set<TObject> serialSelect(Store store, String key, long record, long timestamp) {
Function evalFunc;
if (Keys.isNavigationKey(key)) {
if (store instanceof AtomicOperation || timestamp != Time.NONE) {
return Operations.traverseKeyRecordOptionalAtomic(key, record, timestamp, store);
} else if (store instanceof AtomicSupport) {
AtomicReference<Set<TObject>> value = new AtomicReference<>(ImmutableSet.of());
AtomicOperations.executeWithRetry((AtomicSupport) store, (atomic) -> {
value.set(Operations.traverseKeyRecordOptionalAtomic(key, record, timestamp, atomic));
});
return value.get();
} else {
throw new UnsupportedOperationException("Cannot fetch the current values of a navigation key using a Store that does not support atomic operations");
}
} else if ((evalFunc = Keys.tryParseFunction(key)) != null) {
String method = Calculations.alias(evalFunc.operation()) + "KeyRecordAtomic";
Number value = Reflection.callStatic(Operations.class, method, evalFunc.key(), record, timestamp, store);
return value != null ? ImmutableSet.of(Convert.javaToThrift(value)) : ImmutableSet.of();
} else if (key.equals(Constants.JSON_RESERVED_IDENTIFIER_NAME)) {
return ImmutableSet.of(Convert.javaToThrift(record));
} else {
Source source;
if (Command.isSet()) {
Strategy strategy = new Strategy(Command.current(), store);
source = strategy.source(key, record);
} else {
source = Source.FIELD;
}
Set<TObject> values;
if (source == Source.RECORD) {
// @formatter:off
Map<String, Set<TObject>> data = timestamp == Time.NONE ? store.select(record) : store.select(record, timestamp);
values = data.getOrDefault(key, ImmutableSet.of());
// @formatter:on
} else if (source == Source.FIELD) {
// @formatter:off
values = timestamp == Time.NONE ? store.select(key, record) : store.select(key, record, timestamp);
// @formatter:on
} else {
// source == Source.INDEX
// @formatter:off
values = timestamp == Time.NONE ? store.gather(key, record) : store.gather(key, record, timestamp);
// @formatter:on
}
return values;
}
}
use of com.cinchapi.concourse.server.storage.AtomicOperation in project concourse by cinchapi.
the class Stores method find.
/**
* Find the records that contain values that are stored for {@code key} and
* satisfy {@code operator} in relation to the specified {@code values} at
* {@code timestamp}.
* <p>
* If the {@code key} is primitive, the store lookup is usually a simple
* {@link Store#find(String, Operator, TObject[]) find}. However, if the key
* is a navigation key, this method will process it by
* {@link #browse(Store, String) browsing} the destination values and
* checking the operator validity of each if and only if the {@code store}
* is an {@link AtomicOperation} or {@link AtomicSupport supports} starting
* one.
* </p>
*
* @param store
* @param timestamp
* @param key
* @param operator
* @param values
* @return the records that satisfy the query
*/
public static Set<Long> find(Store store, long timestamp, String key, Operator operator, TObject... values) {
for (int i = 0; i < values.length; ++i) {
TObject value = values[i];
if (value.getType() == Type.FUNCTION) {
Function function = (Function) Convert.thriftToJava(value);
TemporalFunction func = (TemporalFunction) function;
String method = Calculations.alias(function.operation());
ArrayBuilder<Object> args = ArrayBuilder.builder();
method += "Key";
args.add(function.key());
if (function instanceof KeyRecordsFunction || function instanceof KeyConditionFunction) {
method += "Records";
Collection<Long> records = function instanceof KeyRecordsFunction ? ((KeyRecordsFunction) function).source() : Finder.instance().visit(((KeyConditionFunction) function).source(), store);
args.add(records);
} else if (!(function instanceof IndexFunction)) {
throw new IllegalStateException("Invalid function value");
}
method += "Atomic";
args.add(func.timestamp());
args.add(store);
values[i] = Convert.javaToThrift(Reflection.callStatic(Operations.class, method, args.build()));
}
}
if (Keys.isNavigationKey(key)) {
Map<TObject, Set<Long>> index = timestamp == Time.NONE ? browse(store, key) : browse(store, key, timestamp);
Set<Long> records = index.entrySet().stream().filter(e -> e.getKey().is(operator, values)).map(e -> e.getValue()).flatMap(Set::stream).collect(Collectors.toCollection(LinkedHashSet::new));
return records;
} else if (Keys.isFunctionKey(key)) {
Set<Long> records = Sets.newLinkedHashSet();
for (long record : store.getAllRecords()) {
Set<TObject> aggregate = select(store, key, record, timestamp);
for (TObject tobject : aggregate) {
if (tobject.is(operator, values)) {
records.add(record);
break;
}
}
}
return records;
} else {
return timestamp == Time.NONE ? store.find(key, operator, values) : store.find(timestamp, key, operator, values);
}
}
use of com.cinchapi.concourse.server.storage.AtomicOperation in project concourse by cinchapi.
the class AtomicOperations method supplyWithRetry.
/**
* Run the {@link AtomicSupplier} within an {@link AtomicOperation} from the
* provided {@code store} and continue to retry execution of the supplier
* until it terminates without failure and a value can be returned.
*
* @param store the {@link AtomicSupport} store from which the
* {@link AtomicOperation} is started
* @param supplier the {@link AtomicSupplier} to run until it succeeds
* @return the return value
*/
public static <T> T supplyWithRetry(AtomicSupport store, AtomicSupplier<T> supplier) {
AtomicOperation atomic = null;
T value = null;
while (atomic == null || !atomic.commit(CommitVersions.next())) {
atomic = store.startAtomicOperation();
try {
value = supplier.supply(atomic);
} catch (AtomicStateException e) {
atomic = null;
}
}
return value;
}
use of com.cinchapi.concourse.server.storage.AtomicOperation in project concourse by cinchapi.
the class ConcourseServer method insertJsonRecord.
@Override
@TranslateClientExceptions
@VerifyAccessToken
@VerifyWritePermission
public boolean insertJsonRecord(String json, long record, AccessToken creds, TransactionToken transaction, String environment) throws TException {
AtomicSupport store = getStore(transaction, environment);
try {
Multimap<String, Object> data = Convert.jsonToJava(json);
AtomicOperation atomic = store.startAtomicOperation();
List<DeferredWrite> deferred = Lists.newArrayList();
return Operations.insertAtomic(data, record, atomic, deferred) && Operations.insertDeferredAtomic(deferred, atomic) && atomic.commit(CommitVersions.next());
} catch (TransactionStateException e) {
throw new TransactionException();
} catch (AtomicStateException e) {
return false;
}
}
use of com.cinchapi.concourse.server.storage.AtomicOperation in project concourse by cinchapi.
the class OperationsTest method testTraceRecordAtomic.
@Test
public void testTraceRecordAtomic() {
AtomicSupport store = getStore();
try {
setupGraph(store);
AtomicOperation atomic = store.startAtomicOperation();
Map<String, Set<Long>> incoming = Operations.traceRecordAtomic(2, Time.NONE, atomic);
Assert.assertEquals(ImmutableMap.of("foo", ImmutableSet.of(1L, 4L), "bar", ImmutableSet.of(3L), "baz", ImmutableSet.of(3L)), incoming);
} finally {
store.stop();
}
}
Aggregations