use of com.cinchapi.concourse.server.model.Text in project concourse by cinchapi.
the class Database method getLookupRecord.
/**
* Return a {@link Record} that is guaranteed to have the present state for
* whether {@code value} is contained for {@code key} in {@code record}. The
* truth of this query can be obtained using the
* {@link Record#contains(com.cinchapi.concourse.server.io.Byteable, com.cinchapi.concourse.server.io.Byteable)}
* method on the returned {@link Record}.
* <p>
* The query answered by this {@link Record} can also be answered by that
* returned from {@link #getTableRecord(Identifier)}
* and {@link #getTableRecord(Identifier, Text)}, but this method will
* attempt to short circuit by not loading {@link Revisions} that don't
* involve {@code record}, {@code key} and {@code value}. As a result, the
* returned {@link Record} is not cached and cannot be reliably used for
* other queries.
* </p>
*
* @param record
* @param key
* @param value
* @return the {@link Record}
*/
private Record<Identifier, Text, Value> getLookupRecord(Identifier record, Text key, Value value) {
masterLock.readLock().lock();
try {
// First, see if there is a cached full or partial Record that can
// allow a lookup to be performed.
Composite c1 = Composite.create(record);
Composite c2 = null;
Composite c3 = null;
Record<Identifier, Text, Value> lookup = tableCache.getIfPresent(c1);
if (lookup == null) {
c2 = Composite.create(record, key);
lookup = tablePartialCache.getIfPresent(c2);
}
if (lookup == null) {
// Create a LookupRecord to handle this, but DO NOT cache it
// since it has no other utility.
c3 = Composite.create(record, key, value);
lookup = new LookupRecord(record, key, value);
for (Segment segment : segments) {
if (segment.table().mightContain(c3)) {
// Whenever it is possible that the LKV exists, we must
// gather Revisions for LK within a Record so the
// current state of LKV can be determined.
segment.table().seek(c2, lookup);
}
}
}
return lookup;
} finally {
masterLock.readLock().unlock();
}
}
use of com.cinchapi.concourse.server.model.Text in project concourse by cinchapi.
the class Segment method acquire.
/**
* Append the {@code write} to this {@link Segment} using the
* {@code executor} to asynchronously write to all the contained
* {@link Block blocks}.
*
* @param write
* @param executor
* @return a {@link Receipt} that contains the {@link Revision Revisions}
* that were created as a consequence of the transfer
* @throws InterruptedException
*/
public Receipt acquire(Write write, AwaitableExecutorService executor) throws InterruptedException {
Preconditions.checkState(isMutable(), "Cannot transfer Writes to an immutable Segment");
writeLock.lock();
try {
// @formatter:off
Identifier record = write.getRecord();
Text key = write.getKey();
Value value = write.getValue();
long version = write.getVersion();
Action type = write.getType();
Receipt.Builder receipt = Receipt.builder();
Runnable[] tasks = Array.containing(() -> {
TableArtifact artifact = table.insert(record, key, value, version, type);
receipt.itemize(artifact);
}, () -> {
IndexArtifact artifact = index.insert(key, value, record, version, type);
receipt.itemize(artifact);
}, () -> {
Collection<CorpusArtifact> artifacts = corpus.insert(key, value, record, version, type);
receipt.itemize(artifacts);
});
// @formatter:on
executor.await((task, error) -> Logger.error("Unexpected error when trying to transfer the following Write to the Database: {}", write, error), tasks);
// CON-587: Set the min/max version of this Segment because it
// cannot be assumed that revisions are inserted in monotonically
// increasing order of version.
maxTs = Math.max(write.getVersion(), maxTs);
minTs = Math.min(write.getVersion(), minTs);
return receipt.build();
} finally {
writeLock.unlock();
}
}
use of com.cinchapi.concourse.server.model.Text in project concourse by cinchapi.
the class Database method select.
@Override
public Map<String, Set<TObject>> select(long record, long timestamp) {
Identifier L = Identifier.of(record);
TableRecord table = getTableRecord(L);
Map<Text, Set<Value>> data = table.getAll(timestamp);
return Transformers.transformTreeMapSet(data, Text::toString, Value::getTObject, Comparators.CASE_INSENSITIVE_STRING_COMPARATOR);
}
use of com.cinchapi.concourse.server.model.Text in project concourse by cinchapi.
the class Database method chronologize.
@Override
public Map<Long, Set<TObject>> chronologize(String key, long record, long start, long end) {
Identifier L = Identifier.of(record);
Text K = Text.wrapCached(key);
TableRecord table = getTableRecord(L);
Map<Long, Set<Value>> data = table.chronologize(K, start, end);
return Transformers.transformMapSet(data, Functions.identity(), Value::getTObject);
}
use of com.cinchapi.concourse.server.model.Text in project concourse by cinchapi.
the class AtomicOperation method grabLocks.
/**
* Check each one of the {@link #intentions} against the
* {@link #durable} and grab the appropriate locks along the way. This
* method will return {@code true} if all expectations are met and all
* necessary locks are grabbed. Otherwise it will return {@code false}, in
* which case this operation should be aborted immediately.
*
* @return {@code true} if all expectations are met and all necessary locks
* are grabbed.
*/
private boolean grabLocks() {
if (isReadOnly()) {
return true;
} else {
// NOTE: If we can't grab a lock immediately because it is held by
// someone else, then we must fail immediately because the
// AtomicOperation can't properly commit.
locks = Maps.newHashMap();
try {
// intentions
for (Token token : writes2Lock) {
if (notifiedAboutVersionChange) {
return false;
}
LockType type;
if (token instanceof RangeToken) {
RangeToken rangeToken = (RangeToken) token;
if (!rangeReads2Lock.isEmpty(rangeToken.getKey())) {
Range<Value> containing = rangeReads2Lock.get(rangeToken.getKey(), rangeToken.getValues()[0]);
if (containing != null) {
rangeReads2Lock.remove(rangeToken.getKey(), containing);
Iterable<Range<Value>> xor = Ranges.xor(Range.singleton(rangeToken.getValues()[0]), containing);
for (Range<Value> range : xor) {
rangeReads2Lock.put(rangeToken.getKey(), range);
}
}
}
type = LockType.RANGE_WRITE;
} else {
reads2Lock.remove(token);
type = LockType.WRITE;
}
LockDescription lock = LockDescription.forToken(token, lockService, rangeLockService, type);
if (lock.getLock().tryLock()) {
locks.put(lock.getToken(), lock);
} else {
return false;
}
}
// grabbed previously.
for (Token token : reads2Lock) {
if (notifiedAboutVersionChange) {
return false;
}
LockDescription lock = LockDescription.forToken(token, lockService, rangeLockService, LockType.READ);
if (lock.getLock().tryLock()) {
locks.put(lock.getToken(), lock);
} else {
return false;
}
}
// grabbed previously.
for (Entry<Text, RangeSet<Value>> entry : rangeReads2Lock.ranges.entrySet()) {
/* (Authorized) */
if (notifiedAboutVersionChange) {
return false;
}
Text key = entry.getKey();
for (Range<Value> range : entry.getValue().asRanges()) {
RangeToken rangeToken = Ranges.convertToRangeToken(key, range);
LockDescription lock = LockDescription.forToken(rangeToken, lockService, rangeLockService, LockType.RANGE_READ);
if (lock.getLock().tryLock()) {
locks.put(lock.getToken(), lock);
} else {
return false;
}
}
}
} catch (NullPointerException e) {
// abort immediately which means that #locks will become null.
return false;
}
return true;
}
}
Aggregations