/*
* Copyright 2015 OrientDB LTD (info--at--orientdb.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.orientechnologies.orient.server.distributed.scenariotest;
import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal;
import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.server.distributed.impl.ODistributedStorage;
import org.junit.Ignore;
import org.junit.Test;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import static org.junit.Assert.assertEquals;
/**
* Checks for consistency on the cluster with these steps:
* - 3 server (quorum=2)
* - record1 is inserted on server1
* - record1 (version 1) is propagated to the other two servers
* - introduce a delay after record locking for all servers (different for each one)
* - the three clients at the same time update the same record on different servers
*
*/
// TODO Temporary Ignored
public class ThreeClientsRecordUpdateWithTransactionsOnMultipleServersScenarioTest extends AbstractScenarioTest {
private final String RECORD_ID = "R001";
private Map<String, Object> hanFields = new HashMap<String, Object>() {
{
put("id", RECORD_ID);
put("firstName", "Han");
put("lastName", "Solo");
}
};
private Map<String, Object> lukeFields = new HashMap<String, Object>() {
{
put("id", RECORD_ID);
put("firstName", "Luke");
put("lastName", "Skywalker");
}
};
private Map<String, Object> darthFields = new HashMap<String, Object>() {
{
put("id", RECORD_ID);
put("firstName", "Darth");
put("lastName", "Vader");
}
};
private Map<String, Object> leiaFields = new HashMap<String, Object>() {
{
put("id", RECORD_ID);
put("firstName", "Leia");
put("lastName", "Organa");
}
};
@Test
@Ignore
public void test() throws Exception {
maxRetries = 10;
init(SERVERS);
prepare(false);
execute();
}
@Override
public void executeTest() throws Exception {
ODatabaseDocumentTx dbServer1 = poolFactory.get(getDatabaseURL(serverInstance.get(0)), "admin", "admin").acquire();
ODatabaseDocumentTx dbServer2 = poolFactory.get(getDatabaseURL(serverInstance.get(1)), "admin", "admin").acquire();
ODatabaseDocumentTx dbServer3 = poolFactory.get(getDatabaseURL(serverInstance.get(2)), "admin", "admin").acquire();
// inserts record1
ODatabaseRecordThreadLocal.INSTANCE.set(dbServer1);
ODocument record1Server1 = new ODocument("Person").fromMap(hanFields);
record1Server1.save();
// waits for propagation of the record on all the servers
waitForInsertedRecordPropagation(RECORD_ID);
// retrieves record1 from server2 and server 3 and checks they're equal
ODocument record1Server2 = retrieveRecord(getDatabaseURL(serverInstance.get(1)), RECORD_ID);
assertEquals(record1Server2.getVersion(), record1Server1.getVersion());
assertEquals(record1Server2.field("id"), record1Server1.field("id"));
assertEquals(record1Server2.field("firstName"), record1Server1.field("firstName"));
assertEquals(record1Server2.field("lastName"), record1Server1.field("lastName"));
ODocument record1Server3 = retrieveRecord(getDatabaseURL(serverInstance.get(2)), RECORD_ID);
assertEquals(record1Server3.getVersion(), record1Server1.getVersion());
assertEquals(record1Server3.field("id"), record1Server1.field("id"));
assertEquals(record1Server3.field("firstName"), record1Server1.field("firstName"));
assertEquals(record1Server3.field("lastName"), record1Server1.field("lastName"));
// gets the actual version of the record1
int actualVersion = record1Server1.getVersion();
System.out.println("Actual version: " + actualVersion);
// sets a delay for operations on distributed storage of all servers
((ODistributedStorage) dbServer1.getStorage()).setEventListener(new AfterRecordLockDelayer("server1", DOCUMENT_WRITE_TIMEOUT));
((ODistributedStorage) dbServer2.getStorage()).setEventListener(new AfterRecordLockDelayer("server2", DOCUMENT_WRITE_TIMEOUT / 4));
((ODistributedStorage) dbServer3.getStorage()).setEventListener(new AfterRecordLockDelayer("server3", DOCUMENT_WRITE_TIMEOUT / 2));
// updates the same record from three different clients, each calling a different server
List<Callable<Void>> clients = new LinkedList<Callable<Void>>();
clients.add(new RecordUpdater(getDatabaseURL(serverInstance.get(0)), record1Server1, lukeFields, true));
clients.add(new RecordUpdater(getDatabaseURL(serverInstance.get(1)), record1Server2, darthFields, true));
clients.add(new RecordUpdater(getDatabaseURL(serverInstance.get(2)), record1Server3, leiaFields, true));
List<Future<Void>> futures = Executors.newCachedThreadPool().invokeAll(clients);
executeFutures(futures);
// checks that record on server3 is the one which wins over the others
waitForUpdatedRecordPropagation(RECORD_ID, "firstName", "Leia");
record1Server1 = retrieveRecord(getDatabaseURL(serverInstance.get(0)), RECORD_ID);
record1Server2 = retrieveRecord(getDatabaseURL(serverInstance.get(1)), RECORD_ID);
record1Server3 = retrieveRecord(getDatabaseURL(serverInstance.get(2)), RECORD_ID);
int finalVersionServer1 = record1Server1.getVersion();
int finalVersionServer2 = record1Server2.getVersion();
int finalVersionServer3 = record1Server3.getVersion();
assertEquals(actualVersion + 1, finalVersionServer1);
assertEquals(actualVersion + 1, finalVersionServer2);
assertEquals(actualVersion + 1, finalVersionServer3);
}
@Override
public String getDatabaseName() {
return "distributed-three-simultaneous-update";
}
}