001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package com.db4o.test.replication.old;
022:
023: import java.util.*;
024:
025: import com.db4o.*;
026: import com.db4o.ext.*;
027: import com.db4o.query.*;
028: import com.db4o.replication.*;
029: import com.db4o.test.*;
030:
031: public class ReplicationFeaturesMain {
032:
033: private final Set _A = new HashSet(1);
034: private final Set _B = new HashSet(1);
035: private final Set _BOTH = new HashSet(2);
036: private final Set _NONE = Collections.EMPTY_SET;
037:
038: private ObjectContainer _containerA;
039: private ObjectContainer _containerB;
040:
041: private Set _direction;
042: private Set _containersToQueryFrom;
043: private Set _containersWithNewObjects;
044: private Set _containersWithChangedObjects;
045: private Set _objectsToPrevailInConflicts;
046:
047: private int _errors;
048: private String _intermittentErrors = "";
049: private int _testCombination;
050:
051: public void configure() {
052: Db4o.configure().generateUUIDs(Integer.MAX_VALUE);
053: Db4o.configure().generateVersionNumbers(Integer.MAX_VALUE);
054: }
055:
056: public void test() {
057:
058: reopenContainers();
059:
060: _A.add("A");
061: _B.add("B");
062: _BOTH.add("A");
063: _BOTH.add("B");
064:
065: // WORK IN PROGRESS:
066: tstDirection(_BOTH);
067: tstDirection(_A);
068: tstDirection(_B);
069:
070: if (_intermittentErrors.length() > 0) {
071: System.err
072: .println("Intermittent errors found in test combinations:"
073: + _intermittentErrors);
074: Test.ensure(false);
075: }
076:
077: // TODO: replication.checkConflict(obj); //(peek)
078: }
079:
080: private void reopenContainers() {
081: _containerA = Test.reOpen();
082: _containerB = Test.replica();
083: }
084:
085: private void tstDirection(Set direction) {
086: _direction = direction;
087:
088: tstQueryingFrom(_BOTH);
089: tstQueryingFrom(_A);
090: tstQueryingFrom(_B);
091: }
092:
093: private void tstQueryingFrom(Set containers) {
094: _containersToQueryFrom = containers;
095:
096: tstWithNewObjectsIn(_BOTH);
097: tstWithNewObjectsIn(_A);
098: tstWithNewObjectsIn(_B);
099: tstWithNewObjectsIn(_NONE);
100: }
101:
102: private void tstWithNewObjectsIn(Set containers) {
103: _containersWithNewObjects = containers;
104:
105: System.out.print(".");
106:
107: tstWithChangedObjectsIn(_BOTH);
108: tstWithChangedObjectsIn(_A);
109: tstWithChangedObjectsIn(_B);
110: tstWithChangedObjectsIn(_NONE);
111: }
112:
113: private void tstWithChangedObjectsIn(Set containers) {
114: _containersWithChangedObjects = containers;
115:
116: tstWithObjectsPrevailingConflicts(_A);
117: tstWithObjectsPrevailingConflicts(_B);
118: tstWithObjectsPrevailingConflicts(_NONE);
119: }
120:
121: private void tstWithObjectsPrevailingConflicts(Set containers) {
122: _objectsToPrevailInConflicts = containers;
123:
124: _testCombination++;
125: if (_testCombination < 0)
126: return; //Use this to skip some combinations and avoid waiting.
127:
128: _errors = 0;
129: while (true) {
130: try {
131: doIt();
132: break;
133: } catch (RuntimeException rx) {
134: _errors++;
135: if (_errors == 10) {
136: printCombination();
137: throw rx;
138: }
139: }
140: }
141: if (_errors > 0)
142: _intermittentErrors += "\n\t Combination: "
143: + _testCombination + " (" + _errors + " errors)";
144: }
145:
146: private void printCombination() {
147: System.err.println("Direction: " + print(_direction));
148: System.err.println("Querying From: "
149: + print(_containersToQueryFrom));
150: System.err.println("New Objects In: "
151: + print(_containersWithNewObjects));
152: System.err.println("Changed Objects In: "
153: + print(_containersWithChangedObjects));
154: System.err.println("Prevailing Conflicts: "
155: + print(_objectsToPrevailInConflicts));
156: }
157:
158: private void doIt() {
159: initState();
160: reopenContainers();
161:
162: performChanges();
163:
164: ReplicationProcess replication = _containerA.ext()
165: .replicationBegin(_containerB,
166: new ReplicationConflictHandler() {
167: public Object resolveConflict(
168: ReplicationProcess process,
169: Object a, Object b) {
170: if (_objectsToPrevailInConflicts
171: .isEmpty())
172: return null;
173: return _objectsToPrevailInConflicts
174: .contains("A") ? a : b;
175: }
176: });
177:
178: if (_direction.size() == 1) {
179: if (_direction.contains("A")) {
180: replication.setDirection(_containerB, _containerA);
181: }
182: if (_direction.contains("B")) {
183: replication.setDirection(_containerA, _containerB);
184: }
185: }
186:
187: if (_containersToQueryFrom.contains("A")) {
188: replicateQueryingFrom(replication, _containerA);
189: }
190: if (_containersToQueryFrom.contains("B")) {
191: replicateQueryingFrom(replication, _containerB);
192: }
193:
194: replication.commit();
195:
196: checkNames();
197: }
198:
199: private void checkNames() {
200: checkNames("A", "A");
201: checkNames("A", "B");
202: checkNames("B", "A");
203: checkNames("B", "B");
204: }
205:
206: private void checkNames(String origin, String inspected) {
207: checkName(container(inspected), "oldFrom" + origin,
208: isOldNameExpected(inspected));
209: checkName(container(inspected), "newFrom" + origin,
210: isNewNameExpected(origin, inspected));
211: checkName(container(inspected), "oldFromAChangedIn" + origin,
212: isChangedNameExpected(origin, inspected));
213: checkName(container(inspected), "oldFromBChangedIn" + origin,
214: isChangedNameExpected(origin, inspected));
215: }
216:
217: private ObjectContainer container(String aOrB) {
218: return aOrB.equals("A") ? _containerA : _containerB;
219: }
220:
221: private boolean isOldNameExpected(String inspected) {
222: if (isChangedNameExpected("A", inspected))
223: return false;
224: if (isChangedNameExpected("B", inspected))
225: return false;
226: return true;
227: }
228:
229: private boolean isNewNameExpected(String origin, String inspected) {
230: if (!_containersWithNewObjects.contains(origin))
231: return false;
232: if (origin.equals(inspected))
233: return true;
234: if (!_containersToQueryFrom.contains(origin))
235: return false;
236: if (!_direction.contains(inspected))
237: return false;
238: return true;
239: }
240:
241: private boolean isChangedNameExpected(String changed,
242: String inspected) {
243: if (!hasChanges(changed))
244: return false;
245:
246: String other = other(inspected);
247: if (prevailedInConflict(other))
248: return isChangedNameExpected(changed, other);
249:
250: if (inspected.equals(changed))
251: return true;
252: if (hasChanges(inspected))
253: return false;
254:
255: if (!_direction.contains(inspected))
256: return false;
257: if (!wasReplicationTriggered())
258: return false;
259:
260: return true;
261: }
262:
263: private boolean prevailedInConflict(String container) {
264: if (!_objectsToPrevailInConflicts.contains(container))
265: return false;
266: if (!_direction.contains(other(container)))
267: return false;
268: if (!wasReplicationTriggered())
269: return false;
270: return true;
271: }
272:
273: private boolean wasReplicationTriggered() {
274: Set containersToTriggerReplication = new HashSet(
275: _containersToQueryFrom);
276: containersToTriggerReplication
277: .retainAll(_containersWithChangedObjects);
278: return !containersToTriggerReplication.isEmpty();
279: }
280:
281: private boolean hasChanges(String container) {
282: return _containersWithChangedObjects.contains(container);
283: }
284:
285: private String other(String aOrB) {
286: return aOrB.equals("A") ? "B" : "A";
287: }
288:
289: private void performChanges() {
290:
291: if (_containersWithNewObjects.contains("A")) {
292: _containerA.set(new Replicated("newFromA"));
293: }
294: if (_containersWithNewObjects.contains("B")) {
295: _containerB.set(new Replicated("newFromB"));
296: }
297:
298: if (_containersWithChangedObjects.contains("A")) {
299: changeObject(_containerA, "oldFromA", "oldFromAChangedInA");
300: changeObject(_containerA, "oldFromB", "oldFromBChangedInA");
301: }
302: if (_containersWithChangedObjects.contains("B")) {
303: changeObject(_containerB, "oldFromA", "oldFromAChangedInB");
304: changeObject(_containerB, "oldFromB", "oldFromBChangedInB");
305: }
306:
307: _containerA.commit();
308: _containerB.commit();
309: }
310:
311: private void changeObject(ObjectContainer container, String name,
312: String newName) {
313: Replicated obj = find(container, name);
314: obj._name = newName;
315: container.set(obj);
316: }
317:
318: private void checkName(ObjectContainer container, String name,
319: boolean isExpected) {
320: Replicated obj = find(container, name);
321: if (isExpected) {
322: ensure(obj != null);
323: } else {
324: ensure(obj == null);
325: }
326: }
327:
328: private Replicated find(ObjectContainer container, String name) {
329: Query q = container.query();
330: q.constrain(Replicated.class);
331: q.descend("_name").constrain(name);
332: ObjectSet set = q.execute();
333: ensure(set.size() < 2);
334: return (Replicated) set.next();
335: }
336:
337: private void initState() {
338: _containerA.commit();
339: _containerB.commit();
340: Test.deleteAll(_containerA);
341: Test.deleteAll(_containerB);
342:
343: _containerA.set(new Replicated("oldFromA"));
344: _containerB.set(new Replicated("oldFromB"));
345:
346: _containerA.commit();
347: _containerB.commit();
348:
349: final ReplicationProcess replication = _containerA.ext()
350: .replicationBegin(_containerB,
351: new ReplicationConflictHandler() {
352: public Object resolveConflict(
353: ReplicationProcess process,
354: Object a, Object b) {
355: return null;
356: }
357: });
358:
359: replicateQueryingFrom(replication, _containerA);
360: replicateQueryingFrom(replication, _containerB);
361:
362: replication.commit();
363: }
364:
365: private static void replicateQueryingFrom(
366: ReplicationProcess replication, ObjectContainer origin) {
367: ObjectSet set = objectsToReplicate(replication, origin);
368: while (set.hasNext()) {
369: Object next = set.next();
370: replication.replicate(next);
371: }
372: }
373:
374: private static ObjectSet objectsToReplicate(
375: ReplicationProcess replication, ObjectContainer origin) {
376: Query q = origin.query();
377: q.constrain(Replicated.class);
378: replication.whereModified(q);
379: return q.execute();
380: }
381:
382: private static void checkAllEqual(ExtObjectContainer con1,
383: ExtObjectContainer con2) {
384: DeepCompare comparator = new DeepCompare();
385:
386: Query q = con1.query();
387: q.constrain(Replicated.class);
388: ObjectSet all = q.execute();
389: while (all.hasNext()) {
390: Object obj1 = all.next();
391: con1.activate(obj1, Integer.MAX_VALUE);
392:
393: Db4oUUID uuid = con1.getObjectInfo(obj1).getUUID();
394: Object obj2 = con2.getByUUID(uuid);
395: con2.activate(obj2, Integer.MAX_VALUE);
396:
397: ensure(comparator.isEqual(obj1, obj2));
398: }
399: }
400:
401: private static void ensure(boolean condition) {
402: if (!condition)
403: throw new RuntimeException();
404: }
405:
406: private String print(Set containerSet) {
407: if (containerSet.isEmpty())
408: return "NONE";
409: if (containerSet.size() == 2)
410: return "BOTH";
411: return (String) containerSet.iterator().next();
412: }
413:
414: }
|