use of com.orientechnologies.orient.core.tx.OTransactionOptimistic in project orientdb by orientechnologies.
the class ODatabaseDocumentTx method begin.
public ODatabaseDocumentTx begin(final OTransaction.TXTYPE iType) {
checkOpeness();
checkIfActive();
if (currentTx.isActive()) {
if (iType == OTransaction.TXTYPE.OPTIMISTIC && currentTx instanceof OTransactionOptimistic) {
currentTx.begin();
return this;
}
currentTx.rollback(true, 0);
}
// CHECK IT'S NOT INSIDE A HOOK
if (!inHook.isEmpty())
throw new IllegalStateException("Cannot begin a transaction while a hook is executing");
// WAKE UP LISTENERS
for (ODatabaseListener listener : browseListeners()) try {
listener.onBeforeTxBegin(this);
} catch (Throwable t) {
OLogManager.instance().error(this, "Error before tx begin", t);
}
switch(iType) {
case NOTX:
setDefaultTransactionMode();
break;
case OPTIMISTIC:
currentTx = new OTransactionOptimistic(this);
break;
case PESSIMISTIC:
throw new UnsupportedOperationException("Pessimistic transaction");
}
currentTx.begin();
return this;
}
use of com.orientechnologies.orient.core.tx.OTransactionOptimistic in project orientdb by orientechnologies.
the class OObjectSerializerHelper method toStream.
/**
* Serialize the user POJO to a ORecordDocument instance.
*
* @param iPojo
* User pojo to serialize
* @param iRecord
* Record where to update
* @param iObj2RecHandler
*/
public static ODocument toStream(final Object iPojo, final ODocument iRecord, final OEntityManager iEntityManager, final OClass schemaClass, final OUserObject2RecordHandler iObj2RecHandler, final ODatabaseObject db, final boolean iSaveOnlyDirty) {
if (iSaveOnlyDirty && !iRecord.isDirty())
return iRecord;
final long timer = Orient.instance().getProfiler().startChrono();
final Integer identityRecord = System.identityHashCode(iRecord);
if (OSerializationThreadLocal.INSTANCE.get().contains(identityRecord))
return iRecord;
OSerializationThreadLocal.INSTANCE.get().add(identityRecord);
OProperty schemaProperty;
final Class<?> pojoClass = iPojo.getClass();
final List<Field> properties = getClassFields(pojoClass);
// CHECK FOR ID BINDING
final Field idField = fieldIds.get(pojoClass);
if (idField != null) {
Object id = getFieldValue(iPojo, idField.getName());
if (id != null) {
// FOUND
if (id instanceof ORecordId) {
ORecordInternal.setIdentity(iRecord, (ORecordId) id);
} else if (id instanceof Number) {
// TREATS AS CLUSTER POSITION
((ORecordId) iRecord.getIdentity()).setClusterId(schemaClass.getDefaultClusterId());
((ORecordId) iRecord.getIdentity()).setClusterPosition(((Number) id).longValue());
} else if (id instanceof String)
((ORecordId) iRecord.getIdentity()).fromString((String) id);
else if (id.getClass().equals(Object.class))
ORecordInternal.setIdentity(iRecord, (ORecordId) id);
else
OLogManager.instance().warn(OObjectSerializerHelper.class, "@Id field has been declared as %s while the supported are: ORID, Number, String, Object", id.getClass());
}
}
// CHECK FOR VERSION BINDING
final Field vField = fieldVersions.get(pojoClass);
boolean versionConfigured = false;
if (vField != null) {
versionConfigured = true;
Object ver = getFieldValue(iPojo, vField.getName());
final int version = convertVersion(ver);
ORecordInternal.setVersion(iRecord, version);
}
if (db.isMVCC() && !versionConfigured && db.getTransaction() instanceof OTransactionOptimistic)
throw new OTransactionException("Cannot involve an object of class '" + pojoClass + "' in an Optimistic Transaction commit because it does not define @Version or @OVersion and therefore cannot handle MVCC");
// SET OBJECT CLASS
iRecord.setClassName(schemaClass != null ? schemaClass.getName() : null);
String fieldName;
Object fieldValue;
// CALL BEFORE MARSHALLING
invokeCallback(iPojo, iRecord, OBeforeSerialization.class);
for (Field p : properties) {
fieldName = p.getName();
if (idField != null && fieldName.equals(idField.getName()))
continue;
if (vField != null && fieldName.equals(vField.getName()))
continue;
fieldValue = serializeFieldValue(getFieldType(iPojo, fieldName), getFieldValue(iPojo, fieldName));
schemaProperty = schemaClass != null ? schemaClass.getProperty(fieldName) : null;
if (fieldValue != null) {
if (isEmbeddedObject(iPojo.getClass(), fieldValue.getClass(), fieldName, iEntityManager)) {
// AUTO CREATE SCHEMA PROPERTY
if (schemaClass == null) {
db.getMetadata().getSchema().createClass(iPojo.getClass());
iRecord.setClassNameIfExists(iPojo.getClass().getSimpleName());
}
if (schemaProperty == null) {
OType t = OType.getTypeByClass(fieldValue.getClass());
if (t == null)
t = OType.EMBEDDED;
schemaProperty = iRecord.getSchemaClass().createProperty(fieldName, t);
}
}
}
fieldValue = typeToStream(fieldValue, schemaProperty != null ? schemaProperty.getType() : null, iEntityManager, iObj2RecHandler, db, iRecord, iSaveOnlyDirty);
iRecord.field(fieldName, fieldValue);
}
iObj2RecHandler.registerUserObject(iPojo, iRecord);
// CALL AFTER MARSHALLING
invokeCallback(iPojo, iRecord, OAfterSerialization.class);
OSerializationThreadLocal.INSTANCE.get().remove(identityRecord);
Orient.instance().getProfiler().stopChrono("Object.toStream", "Serialize object to stream", timer);
return iRecord;
}
use of com.orientechnologies.orient.core.tx.OTransactionOptimistic in project orientdb by orientechnologies.
the class OObjectEntitySerializer method toStream.
/**
* Serialize the user POJO to a ORecordDocument instance.
*
* @param iPojo
* User pojo to serialize
* @throws IllegalAccessException
* @throws IllegalArgumentException
*/
@SuppressWarnings("unchecked")
protected static <T> T toStream(final T iPojo, final Proxy iProxiedPojo, ODatabaseObject db) throws IllegalArgumentException, IllegalAccessException {
final ODocument iRecord = getDocument(iProxiedPojo);
final long timer = Orient.instance().getProfiler().startChrono();
final Integer identityRecord = System.identityHashCode(iPojo);
if (OObjectSerializationThreadLocal.INSTANCE.get().containsKey(identityRecord))
return (T) OObjectSerializationThreadLocal.INSTANCE.get().get(identityRecord);
OObjectSerializationThreadLocal.INSTANCE.get().put(identityRecord, iProxiedPojo);
OProperty schemaProperty;
final Class<?> pojoClass = iPojo.getClass();
final OClass schemaClass = iRecord.getSchemaClass();
// CHECK FOR ID BINDING
final Field idField = getIdField(pojoClass);
if (idField != null) {
Object id = getFieldValue(idField, iPojo);
if (id != null) {
// FOUND
if (id instanceof ORecordId) {
ORecordInternal.setIdentity(iRecord, (ORecordId) id);
} else if (id instanceof Number) {
// TREATS AS CLUSTER POSITION
((ORecordId) iRecord.getIdentity()).setClusterId(schemaClass.getDefaultClusterId());
((ORecordId) iRecord.getIdentity()).setClusterPosition(((Number) id).longValue());
} else if (id instanceof String)
((ORecordId) iRecord.getIdentity()).fromString((String) id);
else if (id.getClass().equals(Object.class))
ORecordInternal.setIdentity(iRecord, (ORecordId) id);
else
OLogManager.instance().warn(OObjectSerializerHelper.class, "@Id field has been declared as %s while the supported are: ORID, Number, String, Object", id.getClass());
}
if (iRecord.getIdentity().isValid() && iRecord.getIdentity().isPersistent())
iRecord.reload();
}
// CHECK FOR VERSION BINDING
final Field vField = getVersionField(pojoClass);
boolean versionConfigured = false;
if (vField != null) {
versionConfigured = true;
Object ver = getFieldValue(vField, iPojo);
if (ver != null) {
// FOUND
int version = iRecord.getVersion();
if (ver instanceof Number) {
// TREATS AS CLUSTER POSITION
version = ((Number) ver).intValue();
} else if (ver instanceof String)
version = Integer.parseInt((String) ver);
else
OLogManager.instance().warn(OObjectSerializerHelper.class, "@Version field has been declared as %s while the supported are: Number, String", ver.getClass());
ORecordInternal.setVersion(iRecord, version);
}
}
if (db.isMVCC() && !versionConfigured && db.getTransaction() instanceof OTransactionOptimistic)
throw new OTransactionException("Cannot involve an object of class '" + pojoClass + "' in an Optimistic Transaction commit because it does not define @Version or @OVersion and therefore cannot handle MVCC");
String fieldName;
Object fieldValue;
// CALL BEFORE MARSHALLING
invokeCallback(pojoClass, iPojo, iRecord, OBeforeSerialization.class);
Class<?> currentClass = pojoClass;
OObjectEntitySerializedSchema serializedSchema = getCurrentSerializedSchema();
while (!currentClass.equals(Object.class) && serializedSchema.classes.contains(pojoClass)) {
for (Field p : getDeclaredFields(currentClass)) {
if (Modifier.isStatic(p.getModifiers()) || Modifier.isNative(p.getModifiers()) || Modifier.isTransient(p.getModifiers()) || p.getType().isAnonymousClass())
continue;
fieldName = p.getName();
List<String> classTransientFields = serializedSchema.transientFields.get(currentClass);
if ((idField != null && fieldName.equals(idField.getName()) || (vField != null && fieldName.equals(vField.getName())) || (classTransientFields != null && classTransientFields.contains(fieldName))))
continue;
fieldValue = getFieldValue(p, iPojo);
if (fieldValue != null && fieldValue.getClass().isAnonymousClass())
continue;
if (isSerializedType(p))
fieldValue = serializeFieldValue(p.getType(), fieldValue);
schemaProperty = schemaClass != null ? schemaClass.getProperty(fieldName) : null;
OType fieldType = schemaProperty != null ? schemaProperty.getType() : getTypeByClass(currentClass, fieldName);
if (fieldValue != null) {
if (isEmbeddedObject(p)) {
// AUTO CREATE SCHEMA CLASS
if (iRecord.getSchemaClass() == null) {
db.getMetadata().getSchema().createClass(iPojo.getClass());
iRecord.setClassNameIfExists(iPojo.getClass().getSimpleName());
}
}
}
fieldValue = typeToStream(fieldValue, fieldType, db, iRecord);
iRecord.field(fieldName, fieldValue, fieldType);
}
currentClass = currentClass.getSuperclass();
if (currentClass == null || currentClass.equals(ODocument.class))
// POJO EXTENDS ODOCUMENT: SPECIAL CASE: AVOID TO CONSIDER
// ODOCUMENT FIELDS
currentClass = Object.class;
}
// CALL AFTER MARSHALLING
invokeCallback(pojoClass, iPojo, iRecord, OAfterSerialization.class);
OObjectSerializationThreadLocal.INSTANCE.get().remove(identityRecord);
Orient.instance().getProfiler().stopChrono("Object.toStream", "Serialize a POJO", timer);
return (T) iProxiedPojo;
}
use of com.orientechnologies.orient.core.tx.OTransactionOptimistic in project orientdb by orientechnologies.
the class OTxTask method execute.
@Override
public Object execute(final ODistributedRequestId requestId, final OServer iServer, ODistributedServerManager iManager, final ODatabaseDocumentInternal database) throws Exception {
ODistributedServerLog.debug(this, iManager.getLocalNodeName(), getNodeSource(), DIRECTION.IN, "Executing transaction db=%s (reqId=%s)...", database.getName(), requestId);
ODatabaseRecordThreadLocal.INSTANCE.set(database);
final ODistributedDatabase ddb = iManager.getMessageService().getDatabase(database.getName());
// CREATE A CONTEXT OF TX
reqContext = ddb.registerTxContext(requestId);
final ODistributedConfiguration dCfg = iManager.getDatabaseConfiguration(database.getName());
result = new OTxTaskResult();
if (tasks.size() == 0)
// RETURN AFTER REGISTERED THE CONTEXT
return result;
database.begin();
try {
final OTransactionOptimistic tx = (OTransactionOptimistic) database.getTransaction();
// REGISTER CREATE FIRST TO RESOLVE TEMP RIDS
for (OAbstractRecordReplicatedTask task : tasks) {
if (task instanceof OCreateRecordTask) {
final OCreateRecordTask createRT = (OCreateRecordTask) task;
final ORecordId rid = createRT.getRid();
if (rid != null && rid.isPersistent()) {
if (rid.getRecord() != null)
// ALREADY CREATED: SKIP REGISTERING IN TX
continue;
}
final int clId = createRT.clusterId > -1 ? createRT.clusterId : createRT.getRid().isValid() ? createRT.getRid().getClusterId() : -1;
final String clusterName = clId > -1 ? database.getClusterNameById(clId) : null;
if (dCfg.isServerContainingCluster(iManager.getLocalNodeName(), clusterName))
tx.addRecord(createRT.getRecord(), ORecordOperation.CREATED, clusterName);
}
}
final List<ORecordId> rids2Lock = new ArrayList<ORecordId>();
// LOCK ALL THE RECORDS FIRST (ORDERED TO AVOID DEADLOCK)
for (OAbstractRecordReplicatedTask task : tasks) rids2Lock.add(task.getRid());
Collections.sort(rids2Lock);
for (ORecordId rid : rids2Lock) reqContext.lock(rid, getRecordLock());
for (OAbstractRecordReplicatedTask task : tasks) {
final Object taskResult;
// CHECK LOCAL CLUSTER IS AVAILABLE ON CURRENT SERVER
if (!task.checkForClusterAvailability(iManager.getLocalNodeName(), dCfg))
// SKIP EXECUTION BECAUSE THE CLUSTER IS NOT ON LOCAL NODE: THIS CAN HAPPENS IN CASE OF DISTRIBUTED TX WITH SHARDING
taskResult = NON_LOCAL_CLUSTER;
else {
task.setLockRecords(false);
task.checkRecordExists();
taskResult = task.execute(requestId, iServer, iManager, database);
reqContext.addUndoTask(task.getUndoTask(requestId));
}
result.results.add(taskResult);
}
database.commit();
// SEND BACK CHANGED VALUE TO UPDATE
for (int i = 0; i < result.results.size(); ++i) {
final Object currentResult = result.results.get(i);
if (currentResult == NON_LOCAL_CLUSTER)
// SKIP IT
continue;
final OAbstractRecordReplicatedTask task = tasks.get(i);
if (task instanceof OCreateRecordTask) {
// SEND RID + VERSION
final OCreateRecordTask t = (OCreateRecordTask) task;
result.results.set(i, new OPlaceholder(t.getRecord()));
} else if (task instanceof OUpdateRecordTask) {
// SEND VERSION
result.results.set(i, task.getRecord().getVersion());
}
}
return result;
} catch (Throwable e) {
// if (e instanceof ODistributedRecordLockedException)
// ddb.dumpLocks();
ODistributedServerLog.debug(this, iManager.getLocalNodeName(), getNodeSource(), DIRECTION.IN, "Rolling back transaction on local server db=%s (reqId=%s error=%s)...", database.getName(), requestId, e);
database.rollback();
// ddb.popTxContext(requestId);
reqContext.unlock();
if (!(e instanceof ONeedRetryException || e instanceof OTransactionException || e instanceof ORecordDuplicatedException || e instanceof ORecordNotFoundException))
// DUMP ONLY GENERIC EXCEPTIONS
ODistributedServerLog.info(this, getNodeSource(), null, DIRECTION.NONE, "Error on distributed transaction commit", e);
return e;
}
}
use of com.orientechnologies.orient.core.tx.OTransactionOptimistic in project orientdb by orientechnologies.
the class ODocument method setDirty.
/**
* Propagates the dirty status to the owner, if any. This happens when the object is embedded in another one.
*/
@Override
public ORecordAbstract setDirty() {
if (_owners != null) {
// PROPAGATES TO THE OWNER
ORecordElement e;
for (WeakReference<ORecordElement> o : _owners) {
e = o.get();
if (e != null)
e.setDirty();
}
} else if (!isDirty())
getDirtyManager().setDirty(this);
// THIS IS IMPORTANT TO BE SURE THAT FIELDS ARE LOADED BEFORE IT'S TOO LATE AND THE RECORD _SOURCE IS NULL
checkForFields();
super.setDirty();
boolean addToChangedList = false;
ORecordElement owner;
if (!isEmbedded())
owner = this;
else {
owner = getOwner();
while (owner != null && owner.getOwner() != null) {
owner = owner.getOwner();
}
}
if (owner instanceof ODocument && ((ODocument) owner).isTrackingChanges() && ((ODocument) owner).getIdentity().isPersistent())
addToChangedList = true;
if (addToChangedList) {
final ODatabaseDocument database = getDatabaseIfDefined();
if (database != null) {
final OTransaction transaction = database.getTransaction();
if (transaction instanceof OTransactionOptimistic) {
OTransactionOptimistic transactionOptimistic = (OTransactionOptimistic) transaction;
transactionOptimistic.addChangedDocument(this);
}
}
}
return this;
}
Aggregations