use of com.orientechnologies.common.util.OCallable in project orientdb by orientechnologies.
the class ODistributedStorage method deleteRecord.
@Override
public OStorageOperationResult<Boolean> deleteRecord(final ORecordId iRecordId, final int iVersion, final int iMode, final ORecordCallback<Boolean> iCallback) {
resetLastValidBackup();
if (OScenarioThreadLocal.INSTANCE.isRunModeDistributed()) {
// ALREADY DISTRIBUTED
return wrapped.deleteRecord(iRecordId, iVersion, iMode, iCallback);
}
checkLocalNodeIsAvailable();
final String clusterName = getClusterNameByRID(iRecordId);
final ODistributedConfiguration dbCfg = distributedConfiguration;
final String localNodeName = dManager.getLocalNodeName();
checkWriteQuorum(dbCfg, clusterName, localNodeName);
try {
checkNodeIsMaster(localNodeName, dbCfg);
final List<String> nodes = dbCfg.getServers(clusterName, null);
if (nodes.isEmpty())
// NO NODES: EXECUTE LOCALLY ONLY
return wrapped.deleteRecord(iRecordId, iVersion, iMode, iCallback);
final Set<String> clusterNames = Collections.singleton(clusterName);
Boolean executionModeSynch = dbCfg.isExecutionModeSynchronous(clusterName);
if (executionModeSynch == null)
executionModeSynch = iMode == 0;
final boolean syncMode = executionModeSynch;
return (OStorageOperationResult<Boolean>) executeRecordOperationInLock(syncMode, iRecordId, new OCallable<Object, OCallable<Void, ODistributedRequestId>>() {
@Override
public Object call(OCallable<Void, ODistributedRequestId> unlockCallback) {
final ODeleteRecordTask task = new ODeleteRecordTask(iRecordId, iVersion);
final OStorageOperationResult<Boolean> localResult;
final boolean executedLocally = nodes.contains(localNodeName);
if (executedLocally) {
// EXECUTE ON LOCAL NODE FIRST
try {
// LOAD CURRENT RECORD
task.checkRecordExists();
localResult = (OStorageOperationResult<Boolean>) OScenarioThreadLocal.executeAsDistributed(new Callable() {
@Override
public Object call() throws Exception {
task.setLastLSN(wrapped.getLSN());
return wrapped.deleteRecord(iRecordId, iVersion, iMode, iCallback);
}
});
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw OException.wrapException(new ODistributedException("Cannot delete record " + iRecordId), e);
}
nodes.remove(localNodeName);
} else
localResult = null;
if (nodes.isEmpty()) {
unlockCallback.call(null);
if (!executedLocally)
throw new ODistributedException("Cannot execute distributed delete on record " + iRecordId + " because no nodes are available");
} else {
final Boolean localResultPayload = localResult != null ? localResult.getResult() : null;
if (syncMode || localResult == null) {
// REPLICATE IT
try {
final ODistributedResponse dResponse = dManager.sendRequest(getName(), clusterNames, nodes, task, dManager.getNextMessageIdCounter(), EXECUTION_MODE.RESPONSE, localResultPayload, unlockCallback);
final Object payload = dResponse.getPayload();
if (payload instanceof Exception) {
if (payload instanceof ORecordNotFoundException) {
// REPAIR THE RECORD IMMEDIATELY
localDistributedDatabase.getDatabaseRepairer().enqueueRepairRecord((ORecordId) ((ORecordNotFoundException) payload).getRid());
}
executeUndoOnLocalServer(dResponse.getRequestId(), task);
if (payload instanceof ONeedRetryException)
throw (ONeedRetryException) payload;
throw OException.wrapException(new ODistributedException("Error on execution distributed delete record"), (Exception) payload);
}
return new OStorageOperationResult<Boolean>(true);
} catch (RuntimeException e) {
executeUndoOnLocalServer(null, task);
throw e;
} catch (Exception e) {
executeUndoOnLocalServer(null, task);
ODatabaseException.wrapException(new ODistributedException("Cannot execute distributed delete record"), e);
}
}
// ASYNCHRONOUS CALL: EXECUTE LOCALLY AND THEN DISTRIBUTE
if (!nodes.isEmpty())
asynchronousExecution(new OAsynchDistributedOperation(getName(), Collections.singleton(clusterName), nodes, task, dManager.getNextMessageIdCounter(), localResultPayload, unlockCallback, null));
}
return localResult;
}
});
} catch (ONeedRetryException e) {
localDistributedDatabase.getDatabaseRepairer().enqueueRepairRecord(iRecordId);
// PASS THROUGH
throw e;
} catch (HazelcastInstanceNotActiveException e) {
throw new OOfflineNodeException("Hazelcast instance is not available");
} catch (HazelcastException e) {
throw new OOfflineNodeException("Hazelcast instance is not available");
} catch (Exception e) {
localDistributedDatabase.getDatabaseRepairer().enqueueRepairRecord(iRecordId);
handleDistributedException("Cannot route DELETE_RECORD operation for %s to the distributed node", e, iRecordId);
// UNREACHABLE
return null;
}
}
use of com.orientechnologies.common.util.OCallable in project orientdb by orientechnologies.
the class ODistributedTransactionManager method executeAsyncTx.
protected void executeAsyncTx(final Set<String> nodes, final OTxTaskResult localResult, final Set<String> involvedClusters, final OAbstractReplicatedTask txTask, final long messageId, final String localNodeName, final OCallable<Void, ODistributedRequestId> afterSendCallback) {
final OAsyncReplicationOk onAsyncReplicationOk = OExecutionThreadLocal.INSTANCE.get().onAsyncReplicationOk;
final OAsyncReplicationError onAsyncReplicationError = storage.getAsyncReplicationError();
// ASYNCHRONOUSLY REPLICATE IT TO ALL THE OTHER NODES
storage.asynchronousExecution(new OAsynchDistributedOperation(storage.getName(), involvedClusters, nodes, txTask, messageId, localResult, afterSendCallback, new OCallable<Object, OPair<ODistributedRequestId, Object>>() {
@Override
public Object call(final OPair<ODistributedRequestId, Object> iArgument) {
try {
final Object value = iArgument.getValue();
final ODistributedRequestId reqId = iArgument.getKey();
if (value instanceof OTxTaskResult) {
// SEND 2-PHASE DISTRIBUTED COMMIT TX
sendTxCompleted(localNodeName, involvedClusters, nodes, reqId, true, txTask.getPartitionKey());
if (onAsyncReplicationOk != null)
onAsyncReplicationOk.onAsyncReplicationOk();
return null;
} else if (value instanceof Exception) {
try {
storage.executeUndoOnLocalServer(reqId, txTask);
if (ODistributedServerLog.isDebugEnabled())
ODistributedServerLog.debug(this, localNodeName, null, ODistributedServerLog.DIRECTION.NONE, "Async distributed transaction failed: %s", value);
// SEND 2-PHASE DISTRIBUTED ROLLBACK TX
sendTxCompleted(localNodeName, involvedClusters, nodes, reqId, false, txTask.getPartitionKey());
if (value instanceof RuntimeException)
throw (RuntimeException) value;
else
throw OException.wrapException(new OTransactionException("Error on execution async distributed transaction"), (Exception) value);
} finally {
if (onAsyncReplicationError != null)
onAsyncReplicationError.onAsyncReplicationError((Throwable) value, 0);
}
}
// UNKNOWN RESPONSE TYPE
if (ODistributedServerLog.isDebugEnabled())
ODistributedServerLog.debug(this, localNodeName, null, ODistributedServerLog.DIRECTION.NONE, "Async distributed transaction error, received unknown response type: %s", iArgument);
throw new OTransactionException("Error on committing async distributed transaction, received unknown response type " + iArgument);
} finally {
try {
afterSendCallback.call(iArgument.getKey());
} catch (Exception e) {
ODistributedServerLog.debug(this, localNodeName, null, ODistributedServerLog.DIRECTION.NONE, "Error on unlocking Async distributed transaction", e);
}
}
}
}));
}
use of com.orientechnologies.common.util.OCallable in project orientdb by orientechnologies.
the class ODistributedAbstractPlugin method installDatabaseOnLocalNode.
protected ODatabaseDocumentTx installDatabaseOnLocalNode(final String databaseName, final String dbPath, final String iNode, final String iDatabaseCompressedFile, final boolean delta, final File uniqueClustersBackupDirectory, final OModifiableDistributedConfiguration cfg) {
ODistributedServerLog.info(this, nodeName, iNode, DIRECTION.IN, "Installing database '%s' to: %s...", databaseName, dbPath);
try {
final File f = new File(iDatabaseCompressedFile);
final File fCompleted = new File(iDatabaseCompressedFile + ".completed");
new File(dbPath).mkdirs();
final ODatabaseDocumentTx db = new ODatabaseDocumentTx("plocal:" + dbPath);
// USES A CUSTOM WRAPPER OF IS TO WAIT FOR FILE IS WRITTEN (ASYNCH)
final FileInputStream in = new FileInputStream(f) {
@Override
public int read() throws IOException {
while (true) {
final int read = super.read();
if (read > -1)
return read;
if (fCompleted.exists())
return 0;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
@Override
public int read(final byte[] b, final int off, final int len) throws IOException {
while (true) {
final int read = super.read(b, off, len);
if (read > 0)
return read;
if (fCompleted.exists())
return 0;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
@Override
public int available() throws IOException {
while (true) {
final int avail = super.available();
if (avail > 0)
return avail;
if (fCompleted.exists())
return 0;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
};
try {
final ODistributedAbstractPlugin me = this;
executeInDistributedDatabaseLock(databaseName, 0, cfg, new OCallable<Void, OModifiableDistributedConfiguration>() {
@Override
public Void call(final OModifiableDistributedConfiguration cfg) {
try {
if (delta) {
new OIncrementalServerSync().importDelta(serverInstance, db, in, iNode);
} else {
// IMPORT FULL DATABASE (LISTENER ONLY FOR DEBUG PURPOSE)
db.restore(in, null, new Callable<Object>() {
@Override
public Object call() throws Exception {
if (uniqueClustersBackupDirectory != null && uniqueClustersBackupDirectory.exists()) {
// NODE THAT WOULD BE LOST IF NOT REPLACED
for (File f : uniqueClustersBackupDirectory.listFiles()) {
final File oldFile = new File(dbPath + "/" + f.getName());
if (oldFile.exists())
oldFile.delete();
// REPLACE IT
if (!f.renameTo(oldFile))
throw new ODistributedException("Cannot restore exclusive cluster file '" + f.getAbsolutePath() + "' into " + oldFile.getAbsolutePath());
}
uniqueClustersBackupDirectory.delete();
}
return null;
}
}, ODistributedServerLog.isDebugEnabled() ? me : null);
}
return null;
} catch (IOException e) {
throw OException.wrapException(new OIOException("Error on distributed sync of database"), e);
}
}
});
} finally {
in.close();
}
getServerInstance().openDatabase(db, "internal", "internal", null, true);
db.reload();
ODistributedServerLog.info(this, nodeName, null, DIRECTION.NONE, "Installed database '%s' (LSN=%s)", databaseName, ((OAbstractPaginatedStorage) db.getStorage().getUnderlying()).getLSN());
return db;
} catch (IOException e) {
ODistributedServerLog.warn(this, nodeName, null, DIRECTION.IN, "Error on copying database '%s' on local server", e, databaseName);
}
return null;
}
use of com.orientechnologies.common.util.OCallable in project orientdb by orientechnologies.
the class HaSyncClusterTest method invokeSyncCluster.
protected Future<Long> invokeSyncCluster(final String localNodeName, final ServerRun server) {
Future<Long> future = executorService.submit(new Callable<Long>() {
@Override
public Long call() throws Exception {
Long countRecors = new Long(0);
String databasePath = server.getDatabasePath(getDatabaseName());
ODatabaseDocumentTx db = new ODatabaseDocumentTx("plocal:" + databasePath);
db.open("admin", "admin");
try {
ODistributedServerManager manager = server.getServerInstance().getDistributedManager();
ODistributedConfiguration databaseConfiguration = manager.getDatabaseConfiguration(getDatabaseName());
int[] persons = db.getMetadata().getSchema().getClass("Person").getClusterIds();
String clusterName = null;
for (int person : persons) {
String clusterNameById = db.getStorage().getPhysicalClusterNameById(person);
String clusterOwner = databaseConfiguration.getClusterOwner(clusterNameById);
if (clusterOwner.equals(localNodeName)) {
clusterName = clusterNameById;
break;
}
}
Assert.assertNotNull(clusterName);
db.command(new OCommandSQL(String.format("HA sync cluster %s", clusterName))).execute();
final ODistributedMessageService messageService = manager.getMessageService();
waitFor(5000, new OCallable<Boolean, Void>() {
@Override
public Boolean call(Void iArgument) {
ODocument messageStats = messageService.getMessageStats();
long heartbeat = 0;
long deploy_cluster = 0;
if (messageStats != null && messageStats.containsField("heartbeat")) {
heartbeat = messageStats.field("heartbeat");
}
if (messageStats != null && messageStats.containsField("deploy_cluster")) {
deploy_cluster = messageStats.field("deploy_cluster");
}
long processed = messageService.getProcessedRequests() - heartbeat - deploy_cluster;
OLogManager.instance().info(this, "Waiting for processed requests to be [%d], actual [%d] with stats [%s] ", NUM_RECORDS, processed, messageStats.toJSON());
return processed >= NUM_RECORDS;
}
}, String.format("Number for processed request should be [%s]", NUM_RECORDS));
List<ODocument> query = db.query(new OSQLSynchQuery("select count(*) from Person"));
countRecors = query.iterator().next().field("count");
} finally {
db.close();
}
return countRecors;
}
});
return future;
}
use of com.orientechnologies.common.util.OCallable in project orientdb by orientechnologies.
the class DeleteAndLazarusScenarioTest method executeTest.
@Override
public void executeTest() throws Exception {
/*
* Test with writeQuorum = majority
*/
banner("Test with writeQuorum = majority");
ODatabaseDocumentTx dbServer1 = poolFactory.get(getDatabaseURL(serverInstance.get(0)), "admin", "admin").acquire();
// changing configuration: readQuorum=2, autoDeploy=false
System.out.print("\nChanging configuration (autoDeploy=false)...");
ODocument cfg = null;
ServerRun server = serverInstance.get(2);
OHazelcastPlugin manager = (OHazelcastPlugin) server.getServerInstance().getDistributedManager();
ODistributedConfiguration databaseConfiguration = manager.getDatabaseConfiguration(getDatabaseName());
cfg = databaseConfiguration.getDocument();
System.out.println("\nConfiguration updated.");
// inserting record r1 and checking consistency on all the servers
try {
ODatabaseRecordThreadLocal.INSTANCE.set(dbServer1);
System.out.print("Inserting record r1...");
new ODocument("Person").fields("id", "R001", "firstName", "Luke", "lastName", "Skywalker").save();
System.out.println("Done.");
} catch (Exception e) {
e.printStackTrace();
fail("Record r1 not inserted!.");
}
waitForInsertedRecordPropagation("R001");
System.out.print("Checking consistency for record r1...");
ODocument r1onServer1 = retrieveRecord(getDatabaseURL(serverInstance.get(0)), "R001");
ODocument r1onServer2 = retrieveRecord(getDatabaseURL(serverInstance.get(1)), "R001");
ODocument r1onServer3 = retrieveRecord(getDatabaseURL(serverInstance.get(2)), "R001");
final ORecordId r1Rid = (ORecordId) r1onServer1.getIdentity();
assertEquals(r1onServer1.field("@version"), r1onServer2.field("@version"));
assertEquals(r1onServer1.field("id"), r1onServer2.field("id"));
assertEquals(r1onServer1.field("firstName"), r1onServer2.field("firstName"));
assertEquals(r1onServer1.field("lastName"), r1onServer2.field("lastName"));
assertEquals(r1onServer2.field("@version"), r1onServer3.field("@version"));
assertEquals(r1onServer2.field("id"), r1onServer3.field("id"));
assertEquals(r1onServer2.field("firstName"), r1onServer3.field("firstName"));
assertEquals(r1onServer2.field("lastName"), r1onServer3.field("lastName"));
System.out.println("\tDone.");
// initial version of the record r1
int initialVersion = r1onServer1.field("@version");
// isolating server3
System.out.println("Network fault on server3.\n");
simulateServerFault(serverInstance.get(2), "net-fault");
assertFalse(serverInstance.get(2).isActive());
// updating r1 in r1* on server3
banner("Updating r1* on server3 (isolated from the the cluster)");
ODatabaseDocumentTx dbServer3 = null;
try {
r1onServer3 = retrieveRecord(getPlocalDatabaseURL(serverInstance.get(2)), "R001");
dbServer3 = new ODatabaseDocumentTx(getPlocalDatabaseURL(serverInstance.get(2))).open("admin", "admin");
r1onServer3.field("firstName", "Darth");
r1onServer3.field("lastName", "Vader");
r1onServer3.save();
System.out.println(r1onServer3.getRecord().toString());
} catch (Exception e) {
e.printStackTrace();
fail();
}
// restarting server3
serverInstance.get(2).startServer(getDistributedServerConfiguration(serverInstance.get(SERVERS - 1)));
System.out.println("Server 3 restarted.");
assertTrue(serverInstance.get(2).isActive());
// reading r1* on server3
dbServer3 = poolFactory.get(getDatabaseURL(serverInstance.get(2)), "admin", "admin").acquire();
try {
r1onServer3 = retrieveRecord(getPlocalDatabaseURL(serverInstance.get(2)), "R001");
} catch (Exception e) {
e.printStackTrace();
} finally {
dbServer3.close();
}
// r1 was not modified both on server1 and server2
r1onServer1 = retrieveRecord(getDatabaseURL(serverInstance.get(0)), "R001");
r1onServer2 = retrieveRecord(getDatabaseURL(serverInstance.get(1)), "R001");
assertEquals(1, r1onServer1.field("@version"));
assertEquals("R001", r1onServer1.field("id"));
assertEquals("Luke", r1onServer1.field("firstName"));
assertEquals("Skywalker", r1onServer1.field("lastName"));
assertEquals(r1onServer1.field("@version"), r1onServer2.field("@version"));
assertEquals(r1onServer1.field("id"), r1onServer2.field("id"));
assertEquals(r1onServer1.field("firstName"), r1onServer2.field("firstName"));
assertEquals(r1onServer1.field("lastName"), r1onServer2.field("lastName"));
// checking we have different values for r1* on server3
assertEquals("R001", r1onServer3.field("id"));
assertEquals("Darth", r1onServer3.field("firstName"));
assertEquals("Vader", r1onServer3.field("lastName"));
assertEquals(initialVersion + 1, r1onServer3.field("@version"));
// shutdown server1
System.out.println("Network fault on server1.\n");
simulateServerFault(serverInstance.get(0), "net-fault");
assertFalse(serverInstance.get(0).isActive());
// delete request on server3 for r1*
dbServer3 = poolFactory.get(getDatabaseURL(serverInstance.get(2)), "admin", "admin").acquire();
try {
dbServer3.command(new OCommandSQL("delete from Person where @rid=#27:0")).execute();
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
dbServer3.close();
}
// restarting server1
serverInstance.get(0).startServer(getDistributedServerConfiguration(serverInstance.get(0)));
System.out.println("Server 1 restarted.");
assertTrue(serverInstance.get(0).isActive());
// r1 is still present both on server1 and server2
r1onServer1 = retrieveRecord(getDatabaseURL(serverInstance.get(0)), "R001");
r1onServer2 = retrieveRecord(getDatabaseURL(serverInstance.get(1)), "R001");
assertEquals(1, r1onServer1.field("@version"));
assertEquals("R001", r1onServer1.field("id"));
assertEquals("Luke", r1onServer1.field("firstName"));
assertEquals("Skywalker", r1onServer1.field("lastName"));
assertEquals(r1onServer1.field("@version"), r1onServer2.field("@version"));
assertEquals(r1onServer1.field("id"), r1onServer2.field("id"));
assertEquals(r1onServer1.field("firstName"), r1onServer2.field("firstName"));
assertEquals(r1onServer1.field("lastName"), r1onServer2.field("lastName"));
// r1* is still present on server3
r1onServer3 = retrieveRecord(getDatabaseURL(serverInstance.get(2)), "R001");
assertEquals(2, r1onServer3.field("@version"));
assertEquals("R001", r1onServer3.field("id"));
assertEquals("Darth", r1onServer3.field("firstName"));
assertEquals("Vader", r1onServer3.field("lastName"));
// delete request on server1 for r1
dbServer1 = poolFactory.get(getRemoteDatabaseURL(serverInstance.get(0)), "admin", "admin").acquire();
try {
Integer result = dbServer1.command(new OCommandSQL("delete from " + r1Rid)).execute();
} catch (Exception e) {
e.printStackTrace();
} finally {
dbServer1.close();
}
// r1 is no more present neither on server1, server2 nor server3
r1onServer1 = retrieveRecord(getDatabaseURL(serverInstance.get(0)), "R001", true, new OCallable<ODocument, ODocument>() {
@Override
public ODocument call(ODocument doc) {
assertEquals(MISSING_DOCUMENT, doc);
return null;
}
});
r1onServer2 = retrieveRecord(getDatabaseURL(serverInstance.get(1)), "R001", true, new OCallable<ODocument, ODocument>() {
@Override
public ODocument call(ODocument doc) {
assertEquals(MISSING_DOCUMENT, doc);
return null;
}
});
r1onServer3 = retrieveRecord(getDatabaseURL(serverInstance.get(2)), "R001", true, new OCallable<ODocument, ODocument>() {
@Override
public ODocument call(ODocument doc) {
assertEquals(MISSING_DOCUMENT, doc);
return null;
}
});
}
Aggregations