Project

General

Profile

1
package eu.dnetlib.xml.database.exist;
2

    
3
import java.io.IOException;
4
import java.util.*;
5

    
6
import eu.dnetlib.xml.database.XMLDatabase;
7
import org.apache.commons.logging.Log;
8
import org.apache.commons.logging.LogFactory;
9
import org.junit.After;
10
import org.junit.Before;
11
import org.junit.Ignore;
12
import org.junit.Test;
13
import org.xmldb.api.base.XMLDBException;
14

    
15
import static org.junit.Assert.*;
16

    
17
/**
18
 * Test the exist wrapper.
19
 *
20
 * @author marko
21
 *
22
 */
23
public class ExistDatabaseTest { // NOPMD by marko on 11/24/08 5:01 PM
24
	/**
25
	 * number of values in stress test profile.
26
	 */
27
	private static final int STRESS_VALUES = 100;
28

    
29
	/**
30
	 * number of times the values are repeated in the stress test.
31
	 */
32
	private static final int STRESS_PROF_LEN = 100;
33

    
34
	/**
35
	 * number of profile writes in stress test.
36
	 */
37
	private static final int STRESS_TIMES = 2000000;
38

    
39
	/**
40
	 * number of collections for stress test.
41
	 */
42
	private static final int STRESS_COLLS = 40;
43

    
44
	/**
45
	 * number of profiles in stress test.
46
	 */
47
	private static final int STRESS_PROFILES = 1000;
48

    
49
	/**
50
	 * parallel tuning.
51
	 */
52
	private static final int VALUE_SCATTER = 7;
53

    
54
	/**
55
	 * parallel tuning.
56
	 */
57
	private static final int QUERY_SCATTER = 5;
58

    
59
	/**
60
	 * test trigger name.
61
	 */
62
	private static final String TEST_TRIGGER = "testTrigger";
63

    
64
	/**
65
	 * number of collections for parallel test.
66
	 */
67
	private static final int PAR_COLLS = 20;
68

    
69
	/**
70
	 * iterations per thread.
71
	 */
72
	private static final int PAR_ITERATIONS = 100;
73

    
74
	/**
75
	 * parallel job executions.
76
	 */
77
	private static final int PAR_TIMES = 100;
78

    
79
	/**
80
	 * logger.
81
	 */
82
	public static final Log log = LogFactory.getLog(ExistDatabaseTest.class); // NOPMD by marko on 11/24/08 5:01 PM
83

    
84
	/**
85
	 * test xml string.
86
	 */
87
	private static final String HELLO_XML = "<hello/>";
88

    
89
	/**
90
	 * test xml content.
91
	 */
92
	private static final String HELLO_XML_CONTENT = "<hello>content</hello>";
93

    
94
	/**
95
	 * test file name.
96
	 */
97
	private static final String EXAMPLE = "example";
98

    
99
	/**
100
	 * trigger test file name.
101
	 */
102
	private static final String TRIGGER_TEST_FILE = "shouldTrigger";
103

    
104
	/**
105
	 * root collection prefix.
106
	 */
107
	private static final String DB_ROOT = "/db";
108

    
109
	/**
110
	 * test collection name.
111
	 */
112
	private static final String DB_TEST = "/db/testCollection";
113

    
114
	/**
115
	 * test other collection name.
116
	 */
117
	private static final String DB_OTHER = "/db/otherCollection";
118

    
119
	/**
120
	 * test sub collection.
121
	 */
122
	private static final String DB_SUB = DB_TEST + "/sub";
123

    
124
	/**
125
	 * xml database under test.
126
	 */
127
	private transient XMLDatabase database;
128

    
129
	/**
130
	 * eXist database under test, viewed only in setUp and tearDown.
131
	 */
132
	private transient ExistDatabase edb;
133

    
134
	/**
135
	 * prepares the database.
136
	 *
137
	 * @throws Exception
138
	 *             exist error
139
	 */
140
	@Before
141
	public void setUp() throws Exception {
142
		edb = new TemporaryExistDatabase();
143
		edb.start();
144
		database = edb;
145
	}
146

    
147
	/**
148
	 * shuts down the database.
149
	 *
150
	 * @throws IOException
151
	 *             happens
152
	 */
153
	@After
154
	public void tearDown() throws IOException {
155
		if (edb != null)
156
			edb.stop();
157
	}
158

    
159
	/**
160
	 * test create.
161
	 *
162
	 * @throws XMLDBException
163
	 *             happens
164
	 */
165
	@Test
166
	public void create() throws XMLDBException {
167
		database.create(EXAMPLE, DB_ROOT, HELLO_XML);
168
		assertEquals("database resource created", true, true);
169
	}
170

    
171
	/**
172
	 * correct behavior is to throw exception on empty file name, because otherwise the file is invisible but the data
173
	 * is inserted in the xml db.
174
	 *
175
	 * @throws XMLDBException
176
	 *             expected
177
	 */
178
	@Test(expected = XMLDBException.class)
179
	public void createEmptyName() throws XMLDBException {
180
		database.create("", DB_ROOT, "<shouldnt_exist/>");
181

    
182
		// code to repeat the bug, shouldn't be executed because of the expected exception
183
		final Iterator<String> res = database.xquery("collection('')/shouldnt_exist");
184

    
185
		assertTrue("shouldn't exist, but it exists",  res.hasNext());
186
		log.info(database.list(DB_ROOT));
187
		assertEquals("file should be listed, with empty file name", 1, database.list(DB_ROOT).size());
188
		assertEquals("file should be listed, with empty file name", "", database.list(DB_ROOT).get(0));
189

    
190
		assertEquals("the file can be retrieved", "<shouldnt_exist/>", database.read("", DB_ROOT));
191
	}
192

    
193
	/**
194
	 * test read.
195
	 *
196
	 * @throws XMLDBException
197
	 *             shouldn't happen
198
	 */
199
	@Test
200
	public void read() throws XMLDBException {
201
		create();
202
		final String res = database.read(EXAMPLE, DB_ROOT);
203
		assertEquals("simple reading", HELLO_XML, res);
204
	}
205

    
206
	/**
207
	 * test read of non existing file.
208
	 *
209
	 * @throws XMLDBException
210
	 *             shouldn't throw exception
211
	 */
212
	@Test
213
	public void readError() throws XMLDBException {
214
		final String res = database.read("nonExisting", DB_ROOT);
215
		assertEquals("expecting null on unexisting", null, res);
216
	}
217

    
218
	/**
219
	 * test remove.
220
	 *
221
	 * @throws XMLDBException
222
	 *             shouldn't throw exception
223
	 */
224
	@Test
225
	public void remove() throws XMLDBException {
226
		database.create(EXAMPLE, DB_ROOT, HELLO_XML);
227
		String res = database.read(EXAMPLE, DB_ROOT);
228
		assertEquals("reading", HELLO_XML, res);
229

    
230
		database.remove(EXAMPLE, DB_ROOT);
231
		res = database.read(EXAMPLE, DB_ROOT);
232
		assertEquals("now it doesn't exist", null, res);
233
	}
234

    
235
	/**
236
	 * delete unexisting file.
237
	 *
238
	 * @throws XMLDBException
239
	 *             could happen
240
	 */
241
	@Test
242
	public void doubleDelete() throws XMLDBException {
243
		database.create(EXAMPLE, DB_ROOT, HELLO_XML);
244
		String res = database.read(EXAMPLE, DB_ROOT);
245
		assertEquals("reading", HELLO_XML, res);
246

    
247
		database.remove(EXAMPLE, DB_ROOT);
248
		res = database.read(EXAMPLE, DB_ROOT);
249
		assertEquals("now it doesn't exist", null, res);
250

    
251
		assertFalse("already exists", database.remove(EXAMPLE, DB_ROOT));
252
	}
253

    
254
	/**
255
	 * update an xml file.
256
	 *
257
	 * @throws XMLDBException
258
	 *             shouldn't happen
259
	 */
260
	@Test
261
	public void update() throws XMLDBException {
262
		database.create(EXAMPLE, DB_ROOT, HELLO_XML);
263
		String res = database.read(EXAMPLE, DB_ROOT);
264
		assertEquals("reading", HELLO_XML, res);
265

    
266
		database.update(EXAMPLE, DB_ROOT, "<world/>");
267
		res = database.read(EXAMPLE, DB_ROOT);
268
		assertEquals("now it doesn't exist", "<world/>", res);
269
	}
270

    
271
	/**
272
	 * update an unexisting file.
273
	 *
274
	 * @throws XMLDBException
275
	 *             expected
276
	 */
277
	@Test(expected = XMLDBException.class)
278
	public void updateError() throws XMLDBException {
279
		database.create(EXAMPLE, DB_ROOT, HELLO_XML);
280
		database.remove(EXAMPLE, DB_ROOT);
281
		final String res = database.read(EXAMPLE, DB_ROOT);
282
		assertEquals("check non existing", null, res);
283

    
284
		database.update(EXAMPLE, DB_ROOT, "<world/>"); // throws
285
	}
286

    
287
	/**
288
	 * test xquery.
289
	 *
290
	 * @throws XMLDBException
291
	 *             shouldn't happen
292
	 */
293
	@Test()
294
	public void query() throws XMLDBException {
295
		database.create(EXAMPLE, DB_ROOT, "<queryTest><one><sub/></one><two/></queryTest>");
296
		final Iterator<String> res = database.xquery("collection('/db')//queryTest/one");
297
		assertTrue("finds only one result", res.hasNext());
298

    
299
		final Iterator<String> res2 = database.xquery("collection('/db')//queryTest/two");
300
		assertTrue("finds only one result",res2.hasNext());
301
		assertEquals("check the correct result", "<two/>", res2.next());
302
	}
303

    
304
	/**
305
	 * create a collection.
306
	 *
307
	 * @throws XMLDBException
308
	 *             shouldn't happen
309
	 */
310
	@Test()
311
	public void createCollection() throws XMLDBException {
312
		database.createCollection(DB_TEST);
313
		database.create(EXAMPLE, DB_TEST, "<col/>");
314

    
315
		final String res = database.read(EXAMPLE, DB_TEST);
316
		assertEquals("check another collection", "<col/>", res);
317
	}
318

    
319
	/**
320
	 * check the existence of a collection.
321
	 *
322
	 * @throws XMLDBException
323
	 *             shouldn't happen
324
	 */
325
	@Test()
326
	public void checkCollection() throws XMLDBException {
327
		createCollection();
328

    
329
		assertTrue("check root", database.collectionExists(DB_ROOT));
330
		assertTrue("check test collection", database.collectionExists(DB_TEST));
331
		assertFalse("check non existing", database.collectionExists("/db/testNonExistingCollection"));
332
	}
333

    
334
	/**
335
	 * shows that a spurious collection create is legal.
336
	 *
337
	 * @throws XMLDBException
338
	 *             shouldn't throw
339
	 */
340
	@Test()
341
	public void createCollectionDuplicate() throws XMLDBException {
342
		database.createCollection(DB_TEST);
343
		database.createCollection(DB_TEST);
344
	}
345

    
346
	/**
347
	 * remove a collection.
348
	 *
349
	 * @throws XMLDBException
350
	 *             shouldn't throw
351
	 */
352
	@Test()
353
	public void removeCollection() throws XMLDBException {
354
		database.createCollection(DB_TEST);
355
		assertTrue("check before remove", database.collectionExists(DB_TEST));
356
		database.removeCollection(DB_TEST);
357
		assertFalse("check after remove", database.collectionExists(DB_TEST));
358
	}
359

    
360
	/**
361
	 * check useless contract with spring.
362
	 */
363
	@Test
364
	public void testIsRunning() {
365
		assertFalse("contract with spring", edb.isRunning());
366
	}
367

    
368
	/**
369
	 * Test a scenario where exist fails to create a database.
370
	 *
371
	 * @throws IOException
372
	 *             happens
373
	 * @throws XMLDBException
374
	 *             happens
375
	 */
376
	@Test(expected = IllegalStateException.class)
377
	public void checkWrongConfigFile() throws IOException, XMLDBException {
378
		edb.stop();
379
		edb = new ExistDatabase();
380
		try {
381
			edb.setConfigFile("/tmp/unexistingfile");
382
			edb.start();
383
			database = edb;
384

    
385
			create();
386
		} finally {
387
			edb = null; // NOPMD - just for junit
388
		}
389
	}
390

    
391
	/**
392
	 * get child collections.
393
	 *
394
	 * @throws XMLDBException
395
	 *             shouldn't happen
396
	 */
397
	@Test
398
	public void testListChildCollections() throws XMLDBException {
399
		database.createCollection(DB_TEST);
400
		assertTrue("check that collection exists", database.collectionExists(DB_TEST));
401

    
402
		final String[] expectedNames = new String[] { "child1", "child2", "child3" };
403
		for (String name : expectedNames)
404
			database.createCollection(DB_TEST + "/" + name);
405

    
406
		final List<String> res = database.listChildCollections(DB_TEST);
407
		// the db doesn't return then in the same order
408
		Collections.sort(res);
409
		assertArrayEquals("check list", expectedNames, res.toArray());
410
	}
411

    
412
	/**
413
	 * check list resources.
414
	 *
415
	 * @throws XMLDBException
416
	 *             shouldn't happen
417
	 */
418
	@Test
419
	public void testList() throws XMLDBException {
420
		database.createCollection(DB_TEST);
421
		assertTrue("collection should exist", database.collectionExists(DB_TEST));
422

    
423
		final String[] expectedNames = new String[] { "name1", "name2", "name3" };
424
		for (String name : expectedNames)
425
			database.create(name, DB_TEST, HELLO_XML);
426

    
427
		final List<String> res = database.list(DB_TEST);
428
		// the db doesn't return then in the same order
429
		Collections.sort(res);
430
		assertArrayEquals("check list", expectedNames, res.toArray());
431
	}
432

    
433
	/**
434
	 * test low-level set trigger.
435
	 *
436
	 * @throws XMLDBException
437
	 *             shouldn't happen
438
	 */
439
	@Test
440
	public void testSetExistTrigger() throws XMLDBException {
441
		final Map<String, String> params = new HashMap<>();
442
		params.put("listenerBean", "pippo");
443

    
444
		database.createCollection(DB_TEST);
445
		edb.setExistTrigger(TestExistTrigger.class, DB_TEST, Arrays.asList("store", "update", "delete"), params);
446

    
447
		// assertNotNull("check that the conf is stored", database.read(ExistDatabase.COLLECTION_XCONF, DB_ROOT + "/system/config" + DB_TEST));
448

    
449
		database.create(TRIGGER_TEST_FILE, DB_TEST, HELLO_XML_CONTENT);
450
		assertEquals("check the the write happened", HELLO_XML_CONTENT, database.read(TRIGGER_TEST_FILE, DB_TEST));
451

    
452
		database.update(TRIGGER_TEST_FILE, DB_TEST, "<hello>new content</hello>");
453

    
454
		database.xquery("for $x in collection('')/hello where $x/text() = 'new content' return update value $x/text() with 'xupdate'");
455
		assertEquals("check the the xupdate happened", "<hello>xupdate</hello>", database.read(TRIGGER_TEST_FILE, DB_TEST));
456
	}
457

    
458
	/**
459
	 * Test high level addTrigger.
460
	 *
461
	 * @throws XMLDBException
462
	 *             shouldn't happen
463
	 */
464
	@Test
465
	public void testRegisterTrigger() throws XMLDBException {
466
		final TestTrigger trigger = new TestTrigger();
467
		trigger.setName(TEST_TRIGGER);
468

    
469
		database.createCollection(DB_TEST);
470
		database.registerTrigger(trigger, DB_TEST);
471

    
472
		assertFalse("check that the tester state is correct", trigger.isCreated());
473

    
474
		database.create(TRIGGER_TEST_FILE, DB_TEST, HELLO_XML_CONTENT);
475
		assertEquals("check the the write happened", HELLO_XML_CONTENT, database.read(TRIGGER_TEST_FILE, DB_TEST));
476
		assertFalse("check that the trigger is not invoked for the update event", trigger.isUpdated());
477
		assertFalse("check that the trigger is not invoked for the deletion event", trigger.isDeleted());
478
		assertTrue("check that the trigger is invoked create", trigger.isCreated());
479
		assertEquals("check file name for create", TRIGGER_TEST_FILE, trigger.getLastFile());
480
		assertEquals("check collection name for create", DB_TEST, trigger.getLastCollection());
481

    
482
		trigger.reset();
483
		assertFalse("check that the tester state is correct", trigger.isUpdated());
484
		database.update(TRIGGER_TEST_FILE, DB_TEST, "<hello>new content</hello>");
485
		assertFalse("check that the trigger is not invoked for the creation event", trigger.isCreated());
486
		assertFalse("check that the trigger is not invoked for the deletion event", trigger.isDeleted());
487
		assertTrue("check that the trigger is invoked for update", trigger.isUpdated());
488
		assertEquals("check file name for update", TRIGGER_TEST_FILE, trigger.getLastFile());
489
		assertEquals("check collection name for update", DB_TEST, trigger.getLastCollection());
490

    
491
		trigger.reset();
492
		database.xquery("for $x in collection('')/hello where $x/text() = 'new content' return update value $x/text() with 'xupdate'");
493
		assertTrue("check that the trigger is invoked for xupdate", trigger.isUpdated());
494
		assertEquals("check file name for xupdate", TRIGGER_TEST_FILE, trigger.getLastFile());
495
		assertEquals("check collection name for xupdate", DB_TEST, trigger.getLastCollection());
496

    
497
		trigger.reset();
498
		assertFalse("check that the tester state is correct", trigger.isDeleted());
499
		database.remove(TRIGGER_TEST_FILE, DB_TEST);
500
		assertFalse("check that the trigger is not invoked for the creation event", trigger.isCreated());
501
		assertFalse("check that the trigger is not invoked for the update event", trigger.isUpdated());
502
		assertNull("check that the file is removed", database.read(TRIGGER_TEST_FILE, DB_TEST));
503
		assertTrue("check that the trigger is invoked for delete", trigger.isDeleted());
504
		assertEquals("check file name for delete", TRIGGER_TEST_FILE, trigger.getLastFile());
505
		assertEquals("check collection name for delete", DB_TEST, trigger.getLastCollection());
506
	}
507

    
508
	/**
509
	 * a trigger configuration file should not be listed as a xml file resource.
510
	 *
511
	 * @throws XMLDBException
512
	 *             shouldn't happen
513
	 */
514
	@Test
515
	public void testListWithTriggerConf() throws XMLDBException {
516
		database.createCollection(DB_TEST);
517
		assertTrue("collection should exist", database.collectionExists(DB_TEST));
518

    
519
		final TestTrigger trigger = new TestTrigger();
520
		trigger.setName(TEST_TRIGGER);
521

    
522
		database.registerTrigger(trigger, DB_TEST);
523

    
524
		final String[] expectedNames = new String[] { "name1", "name2", "name3" };
525
		for (String name : expectedNames)
526
			database.create(name, DB_TEST, HELLO_XML);
527

    
528
		assertTrue("check that trigger was invoked", trigger.isCreated());
529

    
530
		final List<String> res = database.list(DB_TEST);
531
		// the db doesn't return then in the same order
532
		Collections.sort(res);
533
		assertArrayEquals("check list", expectedNames, res.toArray());
534
	}
535

    
536
	/**
537
	 * test trigger with several collections.
538
	 *
539
	 * @throws XMLDBException
540
	 *             shoudn't happen
541
	 */
542
	@Test
543
	public void testTriggerDifferentCollections() throws XMLDBException {
544
		final TestTrigger trigger = new TestTrigger();
545
		trigger.setName(TEST_TRIGGER);
546

    
547
		database.createCollection(DB_TEST);
548
		database.createCollection(DB_OTHER);
549
		database.createCollection(DB_SUB);
550

    
551
		database.registerTrigger(trigger, DB_TEST);
552
		database.create(TRIGGER_TEST_FILE, DB_TEST, HELLO_XML);
553
		assertTrue("trigger was registered for this collection", trigger.isCreated());
554

    
555
		trigger.reset();
556
		database.create(TRIGGER_TEST_FILE, DB_OTHER, HELLO_XML);
557
		assertFalse("trigger was not registered for this collection", trigger.isCreated());
558

    
559
		trigger.reset();
560
		database.registerTrigger(trigger, DB_OTHER);
561
		database.remove(TRIGGER_TEST_FILE, DB_OTHER);
562
		assertTrue("trigger is now registered for this collection", trigger.isDeleted());
563

    
564
		trigger.reset();
565
		database.create(TRIGGER_TEST_FILE, DB_SUB, HELLO_XML);
566
		assertTrue("trigger is automatically registered for the sub collection", trigger.isCreated());
567

    
568
	}
569

    
570
	/**
571
	 * fails because eXist wants that all collection paths begin with /db.
572
	 *
573
	 * @throws XMLDBException
574
	 *             expected
575
	 */
576
	@Test(expected = XMLDBException.class)
577
	public void testGetCollection() throws XMLDBException {
578
		edb.getCollection("/something");
579
		assertNotNull("dummy", edb);
580
	}
581

    
582
	/**
583
	 * simple parallel job.
584
	 *
585
	 * @author marko
586
	 *
587
	 */
588
	class SimpleParallelJob extends Thread { // NOPMD
589
		/**
590
		 * some argument.
591
		 */
592
		private final transient int name;
593
		/**
594
		 * record eventual exceptions.
595
		 */
596
		private transient Throwable throwable = null;
597

    
598
		/**
599
		 * pass some argument to the job.
600
		 *
601
		 * @param name
602
		 *            some argument
603
		 */
604
		SimpleParallelJob(final int name) {
605
			super();
606
			this.name = name;
607
		}
608

    
609
		/**
610
		 * {@inheritDoc}
611
		 *
612
		 * @see java.lang.Runnable#run()
613
		 */
614
		@Override
615
		public void run() {
616
			try {
617
				parallelJob(name);
618
			} catch (XMLDBException e) {
619
				log.fatal("parallel job failing", e);
620
				throwable = e;
621
			} catch (Throwable e) { // NOPMD
622
				log.fatal("other exception", e);
623
				throwable = e;
624
			}
625
		}
626

    
627
		public Throwable getThrowable() {
628
			return throwable;
629
		}
630
	}
631

    
632
	/**
633
	 * stress test the eXist db.
634
	 *
635
	 * @throws Throwable
636
	 *             could
637
	 */
638
	@Test
639
	public void testParallel() throws Throwable {
640
		final TestTrigger trigger = new TestTrigger();
641
		trigger.setName(TEST_TRIGGER);
642

    
643
		database.registerTrigger(trigger, DB_ROOT);
644

    
645
		final List<SimpleParallelJob> threads = new ArrayList<>(); // NOPMD
646
		for (int i = 0; i < PAR_TIMES; i++)
647
			threads.add(new SimpleParallelJob(i)); // NOPMD
648
		for (Thread thread : threads) { // NOPMD
649
			thread.start();
650
		}
651
		for (Thread thread : threads) { // NOPMD
652
			thread.join();
653
		}
654

    
655
		for (SimpleParallelJob thread : threads) { // NOPMD
656
			if (thread.getThrowable() != null)
657
				throw thread.getThrowable();
658
		}
659

    
660
		assertNotNull("dummy", threads);
661
	}
662

    
663
	/**
664
	 * Stress test for eXist WAL logs.
665
	 *
666
	 * @throws XMLDBException
667
	 *             could happen
668
	 */
669
	@Test
670
	@Ignore
671
	public void testManueleStress() throws XMLDBException {
672
		final StringBuffer childTemplate = new StringBuffer(200); // NOPMD
673

    
674
		for (int i = 0; i < STRESS_VALUES; i++) {
675
			childTemplate.append("<key>" + i + "-VAL</key><value>ITER</value>");
676
		}
677

    
678
		final StringBuffer hugeTemplate = new StringBuffer(200);
679
		hugeTemplate.append("<root>");
680
		for (int i = 0; i < STRESS_PROF_LEN; i++) {
681
			final String child = childTemplate.toString().replace("VAL", Integer.toString(i));
682
			hugeTemplate.append(child);
683
		}
684
		hugeTemplate.append("</root>");
685

    
686
		for (int i = 0; i < STRESS_TIMES; i++) {
687
			final String huge = hugeTemplate.toString().replace("ITER", Integer.toString(i));
688
			database.create("stressTest-" + (i % STRESS_PROFILES), DB_ROOT + "/" + (i % STRESS_COLLS), huge);
689
		}
690

    
691
		assertNotNull("dummy", hugeTemplate);
692
	}
693

    
694
	/**
695
	 * one parallel job execution.
696
	 *
697
	 * @param arg
698
	 *            some argument
699
	 * @throws XMLDBException
700
	 *             could happen.
701
	 */
702
	protected void parallelJob(final int arg) throws XMLDBException {
703
		final String name = Integer.toString(arg);
704
		final String coll = DB_ROOT + "/" + Integer.toString(arg % PAR_COLLS);
705
		database.create(name, coll, "<a" + name + "/>");
706

    
707
		for (int i = 0; i < PAR_ITERATIONS; i++) {
708
			database.update(name, coll, "<a" + name + " value=\"" + i % VALUE_SCATTER + "\"/>");
709
			final Iterator<String> res = database.xquery("collection('')//*[@value='" + i % QUERY_SCATTER + "']");
710
			while (res.hasNext())
711
				res.next();
712
		}
713
	}
714

    
715
}
(3-3/6)