@SuppressWarnings("unchecked") @Test public void checkVersionsInConnectedDocuments() { ODatabaseDocumentTx db = new ODatabaseDocumentTx(url); db.open("admin", "admin"); db.begin(); ODocument kim = new ODocument("Profile").field("name", "Kim").field("surname", "Bauer"); ODocument teri = new ODocument("Profile").field("name", "Teri").field("surname", "Bauer"); ODocument jack = new ODocument("Profile").field("name", "Jack").field("surname", "Bauer"); ((HashSet<ODocument>) jack.field("following", new HashSet<ODocument>()).field("following")) .add(kim); ((HashSet<ODocument>) kim.field("following", new HashSet<ODocument>()).field("following")) .add(teri); ((HashSet<ODocument>) teri.field("following", new HashSet<ODocument>()).field("following")) .add(jack); jack.save(); db.commit(); db.close(); db.open("admin", "admin"); ODocument loadedJack = db.load(jack.getIdentity()); ORecordVersion jackLastVersion = loadedJack.getRecordVersion().copy(); db.begin(); loadedJack.field("occupation", "agent"); loadedJack.save(); db.commit(); Assert.assertTrue(!jackLastVersion.equals(loadedJack.getRecordVersion())); loadedJack = db.load(jack.getIdentity()); Assert.assertTrue(!jackLastVersion.equals(loadedJack.getRecordVersion())); db.close(); db.open("admin", "admin"); loadedJack = db.load(jack.getIdentity()); Assert.assertTrue(!jackLastVersion.equals(loadedJack.getRecordVersion())); db.close(); }
public void testReallocateWrongPlacedReplicasStateNodeRecordsTenRecordsTwoRecordsIsOutOfDate() { final ONodeId idToStart = ONodeId.generateUniqueId(); final ONodeId nodeId = ONodeId.generateUniqueId(); final ONodeId successorNodeId = ONodeId.generateUniqueId(); final ONodeAddressStub nodeAddressStub = new ONodeAddressStub(nodeId); when(nodeLocal.state()).thenReturn(ODHTNode.NodeState.PRODUCTION); when(nodeLocal.getNodeAddress()).thenReturn(nodeAddressStub); final ORID startRecordId = new ORecordId(1, new OClusterPositionNodeId(idToStart)); final ORID nextRecordId = startRecordId.nextRid(); final Iterator<ORecordMetadata> metadataIterator = mock(Iterator.class); when(nodeLocal.getLocalRingIterator(STORAGE_NAME, startRecordId.nextRid(), startRecordId)) .thenReturn(metadataIterator); when(metadataIterator.hasNext()).thenReturn(true); when(metadataIterator.next()) .thenReturn(new ORecordMetadata(nextRecordId, new ODistributedVersion(0))); when(nodeLocal.findSuccessor( ((OClusterPositionNodeId) nextRecordId.getClusterPosition()).getNodeId())) .thenReturn(new ONodeAddressStub(successorNodeId)); final ODHTNode successorNode = mock(ODHTNode.class); when(nodeLookup.findById(new ONodeAddressStub(successorNodeId))).thenReturn(successorNode); final ONodeAddress[] recordSuccessors = new ONodeAddress[] { new ONodeAddressStub(ONodeId.generateUniqueId()), new ONodeAddressStub(ONodeId.generateUniqueId()), new ONodeAddressStub(ONodeId.generateUniqueId()) }; when(successorNode.getSuccessors()).thenReturn(recordSuccessors); when(replicaDistributionStrategy.chooseReplicas(recordSuccessors, 2, 1)) .thenReturn( new Set[] { new HashSet<ONodeAddress>(Arrays.asList(recordSuccessors[0])), new HashSet<ONodeAddress>(Arrays.asList(recordSuccessors[1])) }); final ArrayList<ODocument> missedRecords = new ArrayList<ODocument>(); final List<ORecordMetadata> missedMetadata = new ArrayList<ORecordMetadata>(); for (int i = 0; i < 10; i++) { final ORecordId missedRid = new ORecordId(1, new OClusterPositionNodeId(ONodeId.generateUniqueId())); final ODocument doc = new ODocument(); doc.setIdentity(missedRid); doc.field("value", "data"); missedRecords.add(doc); missedMetadata.add(new ORecordMetadata(missedRid, doc.getRecordVersion())); } when(nodeLocal.getLocalRingIterator( STORAGE_NAME, startRecordId, new ORecordId(1, new OClusterPositionNodeId(successorNodeId)))) .thenReturn(missedMetadata.iterator()); final ODHTNode firstReplicaHolder = mock(ODHTNode.class); final ODHTNode secondReplicaHolder = mock(ODHTNode.class); when(nodeLookup.findById(recordSuccessors[0])).thenReturn(firstReplicaHolder); when(nodeLookup.findById(recordSuccessors[1])).thenReturn(secondReplicaHolder); final ORID[] missedIDs = new ORID[10]; for (int i = 0; i < 10; i++) missedIDs[i] = missedMetadata.get(i).getRid(); when(successorNode.findMissedRecords( STORAGE_NAME, missedMetadata.toArray(new ORecordMetadata[0]))) .thenReturn(missedIDs); when(firstReplicaHolder.findMissedRecords( STORAGE_NAME, missedMetadata.toArray(new ORecordMetadata[0]))) .thenReturn(missedIDs); when(secondReplicaHolder.findMissedRecords( STORAGE_NAME, missedMetadata.toArray(new ORecordMetadata[0]))) .thenReturn(missedIDs); for (ODocument missedRecord : missedRecords) when((ORecordInternal) nodeLocal.readRecordLocal(STORAGE_NAME, missedRecord.getIdentity())) .thenReturn(missedRecord); final ODocument outOfDateRecordOne = missedRecords.get(2); final ODocument outOfDateRecordTwo = missedRecords.get(3); doThrow( new OConcurrentModificationException( outOfDateRecordOne.getIdentity(), new ODistributedVersion(0), outOfDateRecordOne.getRecordVersion(), 0)) .when(nodeLocal) .cleanOutRecord( STORAGE_NAME, outOfDateRecordOne.getIdentity(), outOfDateRecordOne.getRecordVersion()); doThrow( new OConcurrentModificationException( outOfDateRecordTwo.getIdentity(), new ODistributedVersion(0), outOfDateRecordTwo.getRecordVersion(), 0)) .when(nodeLocal) .cleanOutRecord( STORAGE_NAME, outOfDateRecordTwo.getIdentity(), outOfDateRecordTwo.getRecordVersion()); final ONodeId result = globalMaintenanceProtocol.reallocateWrongPlacedReplicas( STORAGE_NAME, CLUSTER_ID, nodeLocal, idToStart, 2, 1); Assert.assertEquals(result, successorNodeId); for (ODocument record : missedRecords) { verify(successorNode).updateReplica(STORAGE_NAME, record, false); verify(firstReplicaHolder).updateReplica(STORAGE_NAME, record, false); verify(secondReplicaHolder).updateReplica(STORAGE_NAME, record, false); verify(nodeLocal) .cleanOutRecord(STORAGE_NAME, record.getIdentity(), record.getRecordVersion()); } }
@Test public void test1RollbackOnConcurrentException() throws IOException { database1 = new ODatabaseDocumentTx(url).open("admin", "admin"); database2 = new ODatabaseDocumentTx(url).open("admin", "admin"); database1.begin(TXTYPE.OPTIMISTIC); // Create docA. ODocument vDocA_db1 = database1.newInstance(); vDocA_db1.field(NAME, "docA"); database1.save(vDocA_db1); // Create docB. ODocument vDocB_db1 = database1.newInstance(); vDocB_db1.field(NAME, "docB"); database1.save(vDocB_db1); database1.commit(); // Keep the IDs. ORID vDocA_Rid = vDocA_db1.getIdentity().copy(); ORID vDocB_Rid = vDocB_db1.getIdentity().copy(); ORecordVersion vDocA_version = OVersionFactory.instance().createUntrackedVersion(); ORecordVersion vDocB_version = OVersionFactory.instance().createUntrackedVersion(); database2.begin(TXTYPE.OPTIMISTIC); try { // Get docA and update in db2 transaction context ODocument vDocA_db2 = database2.load(vDocA_Rid); vDocA_db2.field(NAME, "docA_v2"); database2.save(vDocA_db2); // Concurrent update docA via database1 -> will throw OConcurrentModificationException at // database2.commit(). database1.begin(TXTYPE.OPTIMISTIC); try { vDocA_db1.field(NAME, "docA_v3"); database1.save(vDocA_db1); database1.commit(); } catch (OConcurrentModificationException e) { Assert.fail("Should not failed here..."); } Assert.assertEquals(vDocA_db1.field(NAME), "docA_v3"); // Keep the last versions. // Following updates should failed and reverted. vDocA_version = vDocA_db1.getRecordVersion(); vDocB_version = vDocB_db1.getRecordVersion(); // Update docB in db2 transaction context -> should be rollbacked. ODocument vDocB_db2 = database2.load(vDocB_Rid); vDocB_db2.field(NAME, "docB_UpdatedInTranscationThatWillBeRollbacked"); database2.save(vDocB_db2); // Will throw OConcurrentModificationException database2.commit(); Assert.fail("Should throw OConcurrentModificationException"); } catch (OConcurrentModificationException e) { database2.rollback(); } // Force reload all (to be sure it is not a cache problem) database1.close(); database2.getStorage().close(); database2 = new ODatabaseDocumentTx(url).open("admin", "admin"); ODocument vDocA_db2 = database2.load(vDocA_Rid); Assert.assertEquals(vDocA_db2.field(NAME), "docA_v3"); Assert.assertEquals(vDocA_db2.getRecordVersion(), vDocA_version); // docB should be in the first state : "docB" ODocument vDocB_db2 = database2.load(vDocB_Rid); Assert.assertEquals(vDocB_db2.field(NAME), "docB"); Assert.assertEquals(vDocB_db2.getRecordVersion(), vDocB_version); database1.close(); database2.close(); }