001: /*
002:
003: * $Id: TestStress.java,v 1.5 2003/09/21 15:49:02 boisvert Exp $
004:
005: *
006:
007: * Package stress test
008:
009: *
010:
011: * Simple db toolkit
012:
013: * Copyright (C) 1999, 2000 Cees de Groot <cg@cdegroot.com>
014:
015: *
016:
017: * This library is free software; you can redistribute it and/or
018:
019: * modify it under the terms of the GNU Library General Public License
020:
021: * as published by the Free Software Foundation; either version 2
022:
023: * of the License, or (at your option) any later version.
024:
025: *
026:
027: * This library is distributed in the hope that it will be useful,
028:
029: * but WITHOUT ANY WARRANTY; without even the implied warranty of
030:
031: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
032:
033: * Library General Public License for more details.
034:
035: *
036:
037: * You should have received a copy of the GNU Library General Public License
038:
039: * along with this library; if not, write to the Free Software Foundation,
040:
041: * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
042:
043: */
044:
045: package jdbm.recman;
046:
047: import jdbm.RecordManager;
048:
049: import jdbm.RecordManagerFactory;
050:
051: import jdbm.helper.ByteArraySerializer;
052:
053: import junit.framework.*;
054:
055: import java.util.Random;
056:
057: /**
058:
059: * This class contains stress tests for this package.
060:
061: */
062:
063: public class TestStress extends TestCase {
064:
065: public TestStress(String name) {
066:
067: super (name);
068:
069: }
070:
071: public void setUp() {
072:
073: TestRecordFile.deleteTestFile();
074:
075: }
076:
077: public void tearDown() {
078:
079: TestRecordFile.deleteTestFile();
080:
081: }
082:
083: // test parameters
084:
085: final int RECORDS = 10000;
086:
087: final int MAXSIZE = 500;
088:
089: final int ROUNDS = 1 * 1000 * 1000;
090:
091: final int RPPROMILLE = ROUNDS / 1000;
092:
093: Random rnd = new Random(42);
094:
095: // holder for record data so we can compare
096:
097: class RecordData {
098:
099: long rowid;
100:
101: int size;
102:
103: byte b;
104:
105: RecordData(long rowid, int size, byte b) {
106:
107: this .rowid = rowid;
108:
109: this .size = size;
110:
111: this .b = b;
112:
113: }
114:
115: public String toString() {
116:
117: return "slot(" + rowid + ",sz=" + size + ",b=" + b + ")";
118:
119: }
120:
121: }
122:
123: private int getRandomAllocatedSlot(RecordData[] d) {
124:
125: int slot = rnd.nextInt(RECORDS);
126:
127: while (d[slot] == null) {
128:
129: slot++;
130:
131: if (slot == RECORDS)
132:
133: slot = 0; // wrap
134:
135: }
136:
137: return slot;
138:
139: }
140:
141: // holder for root records
142:
143: long[] roots = new long[FileHeader.NROOTS];
144:
145: private int getRandomAllocatedRoot() {
146:
147: int slot = rnd.nextInt(FileHeader.NROOTS);
148:
149: while (roots[slot] == 0) {
150:
151: slot++;
152:
153: if (slot == FileHeader.NROOTS)
154:
155: slot = 0; // wrap
156:
157: }
158:
159: return slot;
160:
161: }
162:
163: /**
164:
165: * Test basics
166:
167: */
168:
169: public void testBasics() throws Exception {
170:
171: RecordManager recman;
172:
173: recman = RecordManagerFactory
174: .createRecordManager(TestRecordFile.testFileName);
175:
176: // as this code is meant to test data structure calculcations
177:
178: // and stuff like that, we may want to disable transactions
179:
180: // that just slow us down.
181:
182: // mgr.disableTransactions();
183:
184: RecordData[] d = new RecordData[RECORDS];
185:
186: int recordCount = 0, rootCount = 0;
187:
188: int inserts = 0, updates = 0, deletes = 0, fetches = 0;
189:
190: int rootgets = 0, rootsets = 0;
191:
192: int slot = -1;
193:
194: try {
195:
196: for (int i = 0; i < ROUNDS; i++) {
197:
198: if ((i % RPPROMILLE) == 0)
199:
200: System.out.print("\rComplete: "
201:
202: + i / RPPROMILLE + "/1000th");
203:
204: // close and re-open a couple of times during the
205:
206: // test, in order to check flushing etcetera.
207:
208: if ((i % (ROUNDS / 5)) == 0) {
209:
210: System.out.print(" (reopened at round "
211:
212: + i / RPPROMILLE + ")");
213:
214: recman.close();
215:
216: recman = RecordManagerFactory
217: .createRecordManager(TestRecordFile.testFileName);
218:
219: // recman.disableTransactions();
220:
221: }
222:
223: // generate a random number and assign ranges to operations:
224:
225: // 0-10 = insert, 20 = delete, 30-50 = update, 51 = set root,
226:
227: // 52 = get root, rest = fetch.
228:
229: int op = rnd.nextInt(100);
230:
231: if (op <= 10) {
232:
233: // INSERT RECORD
234:
235: if (recordCount == RECORDS) {
236:
237: i -= 1;
238:
239: continue;
240:
241: }
242:
243: slot = 0;
244:
245: while (d[slot] != null)
246:
247: slot++;
248:
249: d[slot] = new RecordData(0, rnd.nextInt(MAXSIZE),
250:
251: (byte) rnd.nextInt());
252:
253: d[slot].rowid =
254:
255: recman.insert(TestUtil.makeRecord(d[slot].size,
256:
257: d[slot].b));
258:
259: recordCount++;
260:
261: inserts++;
262:
263: }
264:
265: else if (op == 20) {
266:
267: // DELETE RECORD
268:
269: if (recordCount == 0) {
270:
271: i -= 1;
272:
273: continue;
274:
275: }
276:
277: slot = getRandomAllocatedSlot(d);
278:
279: recman.delete(d[slot].rowid);
280:
281: d[slot] = null;
282:
283: recordCount--;
284:
285: deletes++;
286:
287: }
288:
289: else if (op <= 50) {
290:
291: // UPDATE RECORD
292:
293: if (recordCount == 0) {
294:
295: i -= 1;
296:
297: continue;
298:
299: }
300:
301: slot = getRandomAllocatedSlot(d);
302:
303: d[slot].size = rnd.nextInt(MAXSIZE);
304:
305: d[slot].b = (byte) rnd.nextInt();
306:
307: recman.update(d[slot].rowid,
308:
309: TestUtil.makeRecord(d[slot].size,
310:
311: d[slot].b));
312:
313: updates++;
314:
315: }
316:
317: else if (op == 51) {
318:
319: // SET ROOT
320:
321: int root = rnd.nextInt(FileHeader.NROOTS);
322:
323: roots[root] = rnd.nextLong();
324:
325: recman.setRoot(root, roots[root]);
326:
327: rootsets++;
328:
329: }
330:
331: else if (op == 52) {
332:
333: // GET ROOT
334:
335: if (rootCount == 0) {
336:
337: i -= 1;
338:
339: continue;
340:
341: }
342:
343: int root = getRandomAllocatedRoot();
344:
345: assertEquals("root", roots[root], recman
346: .getRoot(root));
347:
348: rootgets++;
349:
350: }
351:
352: else {
353:
354: // FETCH RECORD
355:
356: if (recordCount == 0) {
357:
358: i -= 1;
359:
360: continue;
361:
362: }
363:
364: slot = getRandomAllocatedSlot(d);
365:
366: byte[] data = (byte[]) recman.fetch(d[slot].rowid,
367: ByteArraySerializer.INSTANCE);
368:
369: assertTrue("fetch round=" + i + ", slot=" + slot
370:
371: + ", " + d[slot],
372:
373: TestUtil.checkRecord(data, d[slot].size, d[slot].b));
374:
375: fetches++;
376:
377: }
378:
379: }
380:
381: recman.close();
382:
383: } catch (Throwable e) {
384:
385: e.printStackTrace();
386:
387: fail("aborting test at slot " + slot + ": " + e);
388:
389: } finally {
390:
391: System.out.println("records : " + recordCount);
392:
393: System.out.println("deletes : " + deletes);
394:
395: System.out.println("inserts : " + inserts);
396:
397: System.out.println("updates : " + updates);
398:
399: System.out.println("fetches : " + fetches);
400:
401: System.out.println("rootget : " + rootgets);
402:
403: System.out.println("rootset : " + rootsets);
404:
405: int totalSize = 0;
406:
407: for (int i = 0; i < RECORDS; i++)
408:
409: if (d[i] != null)
410:
411: totalSize += d[i].size;
412:
413: System.out.println("total outstanding size: " + totalSize);
414:
415: //System.out.println("---");
416:
417: //for (int i = 0; i < RECORDS; i++)
418:
419: // if (d[i] != null)
420:
421: // System.out.println("slot " + i + ": " + d[i]);
422:
423: }
424:
425: }
426:
427: /**
428:
429: * Runs all tests in this class
430:
431: */
432:
433: public static void main(String[] args) {
434:
435: junit.textui.TestRunner.run(new TestSuite(TestStress.class));
436:
437: }
438:
439: }
|