use of com.eightkdata.mongowp.Status in project torodb by torodb.
the class TorodbSafeRequestProcessor method execute.
@Override
public <A, R> Status<R> execute(Request req, Command<? super A, ? super R> command, A arg, MongodConnection connection) {
mongodMetrics.getCommands().mark();
Timer timer = mongodMetrics.getTimer(command);
try (Timer.Context ctx = timer.time()) {
Callable<Status<R>> callable;
RequiredTransaction commandType = commandsLibrary.getCommandType(command);
switch(commandType) {
case NO_TRANSACTION:
callable = () -> {
return connection.getCommandsExecutor().execute(req, command, arg, connection);
};
break;
case READ_TRANSACTION:
callable = () -> {
try (ReadOnlyMongodTransaction trans = connection.openReadOnlyTransaction()) {
return trans.execute(req, command, arg);
}
};
break;
case WRITE_TRANSACTION:
callable = () -> {
try (WriteMongodTransaction trans = connection.openWriteTransaction(true)) {
Status<R> result = trans.execute(req, command, arg);
if (result.isOk()) {
trans.commit();
}
return result;
}
};
break;
case EXCLUSIVE_WRITE_TRANSACTION:
callable = () -> {
try (ExclusiveWriteMongodTransaction trans = connection.openExclusiveWriteTransaction(true)) {
Status<R> result = trans.execute(req, command, arg);
if (result.isOk()) {
trans.commit();
}
return result;
}
};
break;
default:
throw new AssertionError("Unexpected command type" + commandType);
}
try {
return retrier.retry(callable);
} catch (RetrierGiveUpException ex) {
return Status.from(ErrorCode.CONFLICTING_OPERATION_IN_PROGRESS, "It was impossible to execute " + command.getCommandName() + " after several attempts");
}
}
}
use of com.eightkdata.mongowp.Status in project torodb by torodb.
the class FindImplementation method apply.
@Override
public Status<FindResult> apply(Request req, Command<? super FindArgument, ? super FindResult> command, FindArgument arg, MongodTransaction context) {
logFindCommand(arg);
BsonDocument filter = arg.getFilter();
Cursor<BsonDocument> cursor;
switch(filter.size()) {
case 0:
{
cursor = context.getTorodTransaction().findAll(req.getDatabase(), arg.getCollection()).asDocCursor().transform(t -> t.getRoot()).transform(ToBsonDocumentTranslator.getInstance());
break;
}
case 1:
{
try {
cursor = getByAttributeCursor(context.getTorodTransaction(), req.getDatabase(), arg.getCollection(), filter).transform(ToBsonDocumentTranslator.getInstance());
} catch (CommandFailed ex) {
return Status.from(ex);
}
break;
}
default:
{
return Status.from(ErrorCode.COMMAND_FAILED, "The given query is not supported right now");
}
}
if (Long.valueOf(arg.getBatchSize()) > (long) Integer.MAX_VALUE) {
return Status.from(ErrorCode.COMMAND_FAILED, "Only batchSize equals or lower than " + Integer.MAX_VALUE + " is supported");
}
OptionalLong batchSize = arg.getEffectiveBatchSize();
List<BsonDocument> batch = cursor.getNextBatch(batchSize.isPresent() ? (int) batchSize.getAsLong() : 101);
cursor.close();
return Status.ok(new FindResult(CursorResult.createSingleBatchCursor(req.getDatabase(), arg.getCollection(), batch.iterator())));
}
use of com.eightkdata.mongowp.Status in project torodb by torodb.
the class UpdateImplementation method apply.
@Override
public Status<UpdateResult> apply(Request req, Command<? super UpdateArgument, ? super UpdateResult> command, UpdateArgument arg, WriteMongodTransaction context) {
UpdateStatus updateStatus = new UpdateStatus();
try {
if (!context.getTorodTransaction().existsCollection(req.getDatabase(), arg.getCollection())) {
context.getTorodTransaction().createIndex(req.getDatabase(), arg.getCollection(), Constants.ID_INDEX, ImmutableList.<IndexFieldInfo>of(new IndexFieldInfo(new AttributeReference(Arrays.asList(new Key[] { new ObjectKey(Constants.ID) })), FieldIndexOrdering.ASC.isAscending())), true);
}
for (UpdateStatement updateStatement : arg.getStatements()) {
BsonDocument query = updateStatement.getQuery();
UpdateAction updateAction = UpdateActionTranslator.translate(updateStatement.getUpdate());
Cursor<ToroDocument> candidatesCursor;
switch(query.size()) {
case 0:
{
candidatesCursor = context.getTorodTransaction().findAll(req.getDatabase(), arg.getCollection()).asDocCursor();
break;
}
case 1:
{
try {
candidatesCursor = findByAttribute(context.getTorodTransaction(), req.getDatabase(), arg.getCollection(), query);
} catch (CommandFailed ex) {
return Status.from(ex);
}
break;
}
default:
{
return Status.from(ErrorCode.COMMAND_FAILED, "The given query is not supported right now");
}
}
if (candidatesCursor.hasNext()) {
try {
Stream<List<ToroDocument>> candidatesbatchStream;
if (updateStatement.isMulti()) {
candidatesbatchStream = StreamSupport.stream(Spliterators.spliteratorUnknownSize(candidatesCursor.batch(100), Spliterator.ORDERED), false);
} else {
candidatesbatchStream = Stream.of(ImmutableList.of(candidatesCursor.next()));
}
Stream<KvDocument> updatedCandidates = candidatesbatchStream.map(candidates -> {
updateStatus.increaseCandidates(candidates.size());
context.getTorodTransaction().delete(req.getDatabase(), arg.getCollection(), candidates);
return candidates;
}).flatMap(l -> l.stream()).map(candidate -> {
try {
updateStatus.increaseUpdated();
return update(updateAction, candidate);
} catch (UserException userException) {
throw new UserWrappedException(userException);
}
});
context.getTorodTransaction().insert(req.getDatabase(), arg.getCollection(), updatedCandidates);
} catch (UserWrappedException userWrappedException) {
throw userWrappedException.getCause();
}
} else if (updateStatement.isUpsert()) {
KvDocument toInsertCandidate;
if (updateAction instanceof SetDocumentUpdateAction) {
toInsertCandidate = ((SetDocumentUpdateAction) updateAction).getNewValue();
} else {
toInsertCandidate = update(updateAction, new ToroDocument(-1, (KvDocument) MongoWpConverter.translate(query)));
}
if (!toInsertCandidate.containsKey(Constants.ID)) {
KvDocument.Builder builder = new KvDocument.Builder();
for (DocEntry<?> entry : toInsertCandidate) {
builder.putValue(entry.getKey(), entry.getValue());
}
builder.putValue(Constants.ID, MongoWpConverter.translate(objectIdFactory.consumeObjectId()));
toInsertCandidate = builder.build();
}
updateStatus.increaseCandidates(1);
updateStatus.increaseCreated(toInsertCandidate.get(Constants.ID));
Stream<KvDocument> toInsertCandidates = Stream.of(toInsertCandidate);
context.getTorodTransaction().insert(req.getDatabase(), arg.getCollection(), toInsertCandidates);
}
}
} catch (UserException ex) {
//TODO: Improve error reporting
return Status.from(ErrorCode.COMMAND_FAILED, ex.getLocalizedMessage());
}
mongodMetrics.getUpdateModified().mark(updateStatus.updated);
mongodMetrics.getUpdateMatched().mark(updateStatus.candidates);
mongodMetrics.getUpdateUpserted().mark(updateStatus.upsertResults.size());
return Status.ok(new UpdateResult(updateStatus.updated, updateStatus.candidates, ImmutableList.copyOf(updateStatus.upsertResults)));
}
use of com.eightkdata.mongowp.Status in project torodb by torodb.
the class DropIndexesImplementation method apply.
@Override
public Status<DropIndexesResult> apply(Request req, Command<? super DropIndexesArgument, ? super DropIndexesResult> command, DropIndexesArgument arg, WriteMongodTransaction context) {
int indexesBefore = (int) context.getTorodTransaction().getIndexesInfo(req.getDatabase(), arg.getCollection()).count();
List<String> indexesToDrop;
if (!arg.isDropAllIndexes()) {
if (!arg.isDropByKeys()) {
if (Constants.ID_INDEX.equals(arg.getIndexToDrop())) {
return Status.from(ErrorCode.INVALID_OPTIONS, "cannot drop _id index");
}
indexesToDrop = Arrays.asList(arg.getIndexToDrop());
} else {
if (arg.getKeys().stream().anyMatch(key -> !(KnownType.contains(key.getType())) || (key.getType() != KnownType.asc.getIndexType() && key.getType() != KnownType.desc.getIndexType()))) {
return getStatusForIndexNotFoundWithKeys(arg);
}
indexesToDrop = context.getTorodTransaction().getIndexesInfo(req.getDatabase(), arg.getCollection()).filter(index -> indexFieldsMatchKeys(index, arg.getKeys())).map(index -> index.getName()).collect(Collectors.toList());
if (indexesToDrop.isEmpty()) {
return getStatusForIndexNotFoundWithKeys(arg);
}
}
} else {
indexesToDrop = context.getTorodTransaction().getIndexesInfo(req.getDatabase(), arg.getCollection()).filter(indexInfo -> !Constants.ID_INDEX.equals(indexInfo.getName())).map(indexInfo -> indexInfo.getName()).collect(Collectors.toList());
}
for (String indexToDrop : indexesToDrop) {
boolean dropped = context.getTorodTransaction().dropIndex(req.getDatabase(), arg.getCollection(), indexToDrop);
if (!dropped) {
return Status.from(ErrorCode.INDEX_NOT_FOUND, "index not found with name [" + indexToDrop + "]");
}
}
return Status.ok(new DropIndexesResult(indexesBefore));
}
use of com.eightkdata.mongowp.Status in project torodb by torodb.
the class DropIndexesReplImpl method apply.
@Override
public Status<DropIndexesResult> apply(Request req, Command<? super DropIndexesArgument, ? super DropIndexesResult> command, DropIndexesArgument arg, SharedWriteTorodTransaction trans) {
int indexesBefore = (int) trans.getIndexesInfo(req.getDatabase(), arg.getCollection()).count();
List<String> indexesToDrop;
if (!arg.isDropAllIndexes()) {
if (!arg.isDropByKeys()) {
if (Constants.ID_INDEX.equals(arg.getIndexToDrop())) {
LOGGER.warn("Trying to drop index {}. Ignoring the whole request", arg.getIndexToDrop());
return Status.ok(new DropIndexesResult(indexesBefore));
}
indexesToDrop = Arrays.asList(arg.getIndexToDrop());
} else {
indexesToDrop = trans.getIndexesInfo(req.getDatabase(), arg.getCollection()).filter(index -> indexFieldsMatchKeys(index, arg.getKeys())).map(index -> index.getName()).collect(Collectors.toList());
if (indexesToDrop.isEmpty()) {
LOGGER.warn("Index not found with keys [" + arg.getKeys().stream().map(key -> '"' + key.getKeys().stream().collect(Collectors.joining(".")) + "\" :" + key.getType().getName()).collect(Collectors.joining(", ")) + "]. Ignoring the whole request", arg.getIndexToDrop());
return Status.ok(new DropIndexesResult(indexesBefore));
}
}
} else {
indexesToDrop = trans.getIndexesInfo(req.getDatabase(), arg.getCollection()).filter(indexInfo -> !Constants.ID_INDEX.equals(indexInfo.getName())).map(indexInfo -> indexInfo.getName()).collect(Collectors.toList());
}
for (String indexToDrop : indexesToDrop) {
LOGGER.info("Dropping index {} on collection {}.{}", req.getDatabase(), arg.getCollection(), indexToDrop);
boolean dropped = trans.dropIndex(req.getDatabase(), arg.getCollection(), indexToDrop);
if (!dropped) {
LOGGER.info("Trying to drop index {}, but it has not been " + "found. This is normal since the index could have been filtered or " + "we are reapplying oplog during a recovery. Ignoring it", indexToDrop);
}
}
return Status.ok(new DropIndexesResult(indexesBefore));
}
Aggregations