diff --git a/core/src/main/java/com/orientechnologies/orient/core/record/impl/ODocument.java b/core/src/main/java/com/orientechnologies/orient/core/record/impl/ODocument.java index a7b96900fd1..2b65b0678cf 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/record/impl/ODocument.java +++ b/core/src/main/java/com/orientechnologies/orient/core/record/impl/ODocument.java @@ -3171,8 +3171,8 @@ protected void unTrack(OIdentifiable id) { super.unTrack(id); } - private Object getDeltaValue(Object originalValue, Object currentValue, boolean changed){ - //TODO review this clause once again + private Object getUpdateDeltaValue(Object currentValue, boolean changed){ + //TODO review this clause once again if (changed || !(currentValue instanceof ODocument)){ return currentValue; } @@ -3184,20 +3184,64 @@ private Object getDeltaValue(Object originalValue, Object currentValue, boolean else{ docVal = (ODocument)currentValue; } - return docVal.getDeltaFromOriginal(); + return docVal.getDeltaFromOriginalForUpdate(); + } + } + + private Object getDeleteDeltaValue(Object currentValue, boolean exist){ + //TODO review this clause once again + if (!exist || !(currentValue instanceof ODocument)){ + return currentValue; + } + else{ + ODocument docVal; + if (currentValue instanceof ODocumentSerializable){ + docVal = ((ODocumentSerializable)currentValue).toDocument(); + } + else{ + docVal = (ODocument)currentValue; + } + return docVal.getDeltaFromOriginalForDelete(); } } - public ODocument getDeltaFromOriginal(){ - ODocument retVal = new ODocument(); + private ODocument getDeltaFromOriginalForUpdate(){ + ODocument updated = new ODocument(); + //get updated and new records for (Map.Entry fieldVal : _fields.entrySet()){ ODocumentEntry val = fieldVal.getValue(); if (val.isChangedTree()){ String fieldName = fieldVal.getKey(); - Object deltaValue = getDeltaValue(val.original, val.value, val.isChanged()); - retVal.field(fieldName, deltaValue); + Object deltaValue = getUpdateDeltaValue(val.value, val.isChanged()); + updated.field(fieldName, deltaValue); + } + } + return updated; + } + + private ODocument getDeltaFromOriginalForDelete(){ + ODocument updated = new ODocument(); + //get updated and new records + for (Map.Entry fieldVal : _fields.entrySet()){ + ODocumentEntry val = fieldVal.getValue(); + if (val.hasNonExistingTree()){ + String fieldName = fieldVal.getKey(); + Object deltaValue = getDeleteDeltaValue(val.value, val.exist()); + updated.field(fieldName, deltaValue); } } - return retVal; + return updated; + } + + public ODocument getDeltaFromOriginal(){ + ODocument ret = new ODocument(); + ODocument updated = getDeltaFromOriginalForUpdate(); + ret.field("u", updated); + + //get deleted delta + ODocument deleted = getDeltaFromOriginalForDelete(); + ret.field("d", deleted); + + return ret; } } diff --git a/core/src/main/java/com/orientechnologies/orient/core/record/impl/ODocumentEntry.java b/core/src/main/java/com/orientechnologies/orient/core/record/impl/ODocumentEntry.java index 705364d5636..f155074dfff 100644 --- a/core/src/main/java/com/orientechnologies/orient/core/record/impl/ODocumentEntry.java +++ b/core/src/main/java/com/orientechnologies/orient/core/record/impl/ODocumentEntry.java @@ -51,8 +51,9 @@ public boolean isChanged() { } public boolean isChangedTree(){ - if (changed) + if (changed && exist){ return true; + } if (value instanceof ODocument){ ODocument doc = (ODocument)value; @@ -65,6 +66,23 @@ public boolean isChangedTree(){ return false; } + + public boolean hasNonExistingTree(){ + if (!exist){ + return true; + } + + if (value instanceof ODocument){ + ODocument doc = (ODocument)value; + for (Map.Entry field : doc._fields.entrySet()){ + if (field.getValue().hasNonExistingTree()){ + return true; + } + } + } + + return false; + } public void setChanged(final boolean changed) { this.changed = changed; diff --git a/core/src/main/java/com/orientechnologies/orient/core/serialization/serializer/record/binary/ORecordSerializerNetworkV37.java b/core/src/main/java/com/orientechnologies/orient/core/serialization/serializer/record/binary/ORecordSerializerNetworkV37.java index 48390fff020..b6d9056dd71 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/serialization/serializer/record/binary/ORecordSerializerNetworkV37.java +++ b/core/src/main/java/com/orientechnologies/orient/core/serialization/serializer/record/binary/ORecordSerializerNetworkV37.java @@ -866,8 +866,15 @@ public byte[] toStream(ORecord iSource, boolean iOnlyDelta) { } else { final BytesContainer container = new BytesContainer(); + ODocument doc = (ODocument) iSource; // SERIALIZE RECORD - serialize((ODocument) iSource, container, false); + if (!iOnlyDelta){ + serialize(doc, container, false); + } + else{ + ODocument deltaDoc = doc.getDeltaFromOriginal(); + serialize(deltaDoc, container, false); + } return container.fitBytes(); } diff --git a/core/src/test/java/com/orientechnologies/orient/core/record/impl/ODocumentTest.java b/core/src/test/java/com/orientechnologies/orient/core/record/impl/ODocumentTest.java index 38c194791bb..2c61d232761 100644 --- a/core/src/test/java/com/orientechnologies/orient/core/record/impl/ODocumentTest.java +++ b/core/src/test/java/com/orientechnologies/orient/core/record/impl/ODocumentTest.java @@ -392,19 +392,31 @@ public void testGetDiffFromOriginalSimple(){ String constantFieldName = "constantField"; String originalValue = "orValue"; String testValue = "testValue"; + String removeField = "removeField"; + doc.field(fieldName, originalValue); doc.field(constantFieldName, "someValue"); + doc.field(removeField, "removeVal"); doc = db.save(doc); // doc._fields.get(fieldName).original = originalValue; // doc._fields.get(constantFieldName).changed = false; doc.field(fieldName, testValue); + doc.removeField(removeField); ODocument dc = doc.getDeltaFromOriginal(); - assertFalse(dc._fields.containsKey(constantFieldName)); - assertTrue(dc._fields.containsKey(fieldName)); - assertEquals(dc.field(fieldName), testValue); + ODocument updatePart = dc.field("u"); + ODocument deletePart = dc.field("d"); + + assertFalse(updatePart._fields.containsKey(constantFieldName)); + assertTrue(updatePart._fields.containsKey(fieldName)); + assertEquals(updatePart.field(fieldName), testValue); + + assertFalse(deletePart._fields.containsKey(constantFieldName)); + assertTrue(deletePart._fields.containsKey(removeField)); + + doc = db.save(doc); db.close(); } diff --git a/distributed/src/main/java/com/orientechnologies/orient/server/distributed/impl/task/OTransactionPhase1Task.java b/distributed/src/main/java/com/orientechnologies/orient/server/distributed/impl/task/OTransactionPhase1Task.java index 6298e744451..f97af7f7b0b 100644 --- a/distributed/src/main/java/com/orientechnologies/orient/server/distributed/impl/task/OTransactionPhase1Task.java +++ b/distributed/src/main/java/com/orientechnologies/orient/server/distributed/impl/task/OTransactionPhase1Task.java @@ -6,7 +6,6 @@ import com.orientechnologies.orient.core.Orient; import com.orientechnologies.orient.core.command.OCommandDistributedReplicateRequest; import com.orientechnologies.orient.core.db.ODatabaseDocumentInternal; -import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal; import com.orientechnologies.orient.core.db.record.ORecordOperation; import com.orientechnologies.orient.core.exception.OConcurrentModificationException; import com.orientechnologies.orient.core.id.ORecordId; @@ -68,7 +67,12 @@ public void genOps(List ops) { request.setId(txEntry.getRecord().getIdentity()); request.setRecordType(ORecordInternal.getRecordType(txEntry.getRecord())); switch (txEntry.type) { - case ORecordOperation.CREATED: + case ORecordOperation.CREATED:{ + byte[] newRec = ORecordSerializerNetworkV37.INSTANCE.toStream(txEntry.getRecord(), false); + request.setRecord(newRec); + request.setContentChanged(ORecordInternal.isContentChanged(txEntry.getRecord())); + } + break; case ORecordOperation.UPDATED: byte[] deltaRec = ORecordSerializerNetworkV37.INSTANCE.toStream(txEntry.getRecord(), true); byte[] newRec = ORecordSerializerNetworkV37.INSTANCE.toStream(txEntry.getRecord(), false); @@ -157,12 +161,16 @@ private void convert(ODatabaseDocumentInternal database) { ORecord record = null; switch (type) { - case ORecordOperation.CREATED: + case ORecordOperation.CREATED:{ + record = ORecordSerializerNetworkV37.INSTANCE.fromStream(req.getRecord(), null, null); + ORecordInternal.setRecordSerializer(record, database.getSerializer()); + } + break; case ORecordOperation.UPDATED: { - record = ORecordSerializerNetworkV37.INSTANCE.fromStream(req.getRecord(), null, null); - ORecordInternal.setRecordSerializer(record, database.getSerializer()); - } - break; + record = ORecordSerializerNetworkV37.INSTANCE.fromStream(req.getRecord(), null, null); + ORecordInternal.setRecordSerializer(record, database.getSerializer()); + } + break; case ORecordOperation.DELETED: record = database.getRecord(req.getId()); if (record == null) { diff --git a/distributed/src/test/java/com/orientechnologies/orient/server/distributed/impl/OTransactionPhase1TaskTest.java b/distributed/src/test/java/com/orientechnologies/orient/server/distributed/impl/OTransactionPhase1TaskTest.java index 30801bd758f..65c4e016617 100755 --- a/distributed/src/test/java/com/orientechnologies/orient/server/distributed/impl/OTransactionPhase1TaskTest.java +++ b/distributed/src/test/java/com/orientechnologies/orient/server/distributed/impl/OTransactionPhase1TaskTest.java @@ -117,7 +117,7 @@ public void testExecutionConcurrentModificationDelete() throws Exception { doc.field("first", "one"); session.save(doc); ODocument old = doc.copy(); - doc.field("first", "two"); + doc.field("first", "two"); session.save(doc); session.getLocalCache().clear();