001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.object.bytecode.hook.impl;
006:
007: import com.tc.exception.ImplementMe;
008: import com.tc.object.ObjectID;
009: import com.tc.object.TCClass;
010: import com.tc.object.TCObject;
011: import com.tc.object.dna.api.DNA;
012: import com.tc.object.dna.api.DNAException;
013: import com.tc.object.dna.api.DNAWriter;
014: import com.tc.util.concurrent.ThreadUtil;
015:
016: import gnu.trove.TLinkable;
017:
018: import java.util.ArrayList;
019: import java.util.IdentityHashMap;
020: import java.util.List;
021: import java.util.Map;
022: import java.util.Random;
023:
024: import junit.framework.TestCase;
025:
026: public class ArrayManagerTest extends TestCase {
027:
028: private final Map registerdPairs = new IdentityHashMap();
029: private static final List errors = new ArrayList();
030: private Object[] arrays;
031:
032: protected void setUp() throws Exception {
033: for (int i = 0; i < 100; i++) {
034: TCObject tco = new FakeTCObject();
035: Object array = new Object[] {};
036: registerdPairs.put(array, tco); // do this before register to always have strong ref
037: ArrayManager.register(array, tco);
038: }
039:
040: arrays = registerdPairs.keySet().toArray();
041: }
042:
043: protected void tearDown() throws Exception {
044: super .tearDown();
045:
046: synchronized (errors) {
047: if (errors.size() > 0) {
048: errors.clear();
049: fail();
050: }
051: }
052: }
053:
054: static void addError(Throwable t) {
055: t.printStackTrace();
056: synchronized (errors) {
057: errors.add(t);
058: }
059: }
060:
061: public void testCache() {
062: Random r = new Random();
063: for (int i = 0; i < 100000; i++) {
064: Object array = arrays[r.nextInt(arrays.length)];
065: TCObject expected = (TCObject) registerdPairs.get(array);
066: assertEquals(expected, ArrayManager.getObject(array));
067: }
068: }
069:
070: public void testReplaceCachedNegative() {
071: List refs = new ArrayList();
072: for (int i = 0; i < 50000; i++) {
073: Object array = new Object[] {};
074: refs.add(array);
075: assertNull(ArrayManager.getObject(array));
076: TCObject tco = new FakeTCObject();
077: ArrayManager.register(array, tco);
078: assertEquals(tco, ArrayManager.getObject(array));
079: assertEquals(tco, ArrayManager.getObject(array)); // do it twice
080: }
081: }
082:
083: public void testThreadsNoGC() throws Exception {
084: testThreads(false);
085: }
086:
087: public void testThreads() throws Exception {
088: testThreads(true);
089: }
090:
091: private void testThreads(boolean withGC) throws Exception {
092: AddNew addNew = new AddNew();
093: Thread adder = new Thread(addNew, "Adder");
094:
095: Query[] query = new Query[2];
096: for (int i = 0; i < query.length; i++) {
097: query[i] = new Query(arrays, registerdPairs, withGC);
098: }
099: Thread[] queries = new Thread[query.length];
100: for (int i = 0; i < queries.length; i++) {
101: queries[i] = new Thread(query[i]);
102: queries[i].setName("Query #" + i);
103: queries[i].start();
104: }
105:
106: adder.start();
107:
108: ThreadUtil.reallySleep(30000);
109:
110: addNew.stop();
111: adder.join();
112:
113: for (int i = 0; i < queries.length; i++) {
114: query[i].stop();
115: }
116: for (int i = 0; i < queries.length; i++) {
117: queries[i].join();
118: }
119:
120: }
121:
122: private static abstract class Base implements Runnable {
123: private volatile boolean stop = false;
124: private int count = 0;
125:
126: public void run() {
127: try {
128: while (!stop) {
129: work();
130: count++;
131: }
132: } catch (Throwable t) {
133: addError(t);
134: } finally {
135: System.err.println(Thread.currentThread().getName()
136: + " made " + count + " loops");
137: }
138: }
139:
140: void stop() {
141: stop = true;
142: }
143:
144: abstract void work() throws Throwable;
145: }
146:
147: private static class Query extends Base {
148: private final Random r = new Random();
149: private final Map pairs;
150: private final Object[] arrays;
151: private final boolean withGC;
152:
153: Query(Object[] arrays, Map pairs, boolean withGC) {
154: this .arrays = arrays;
155: this .pairs = pairs;
156: this .withGC = withGC;
157: }
158:
159: void work() throws Throwable {
160: if (r.nextBoolean()) {
161: Object array = arrays[r.nextInt(arrays.length)];
162: TCObject expect = (TCObject) pairs.get(array);
163: if (expect != ArrayManager.getObject(array)) {
164: throw new AssertionError("wrong mapping returned");
165: }
166: } else {
167: if (ArrayManager.getObject(new Object[] {}) != null) {
168: throw new AssertionError(
169: "found object for brand new array");
170: }
171: }
172:
173: if (withGC && (System.currentTimeMillis() % 255) == 0) {
174: System.out.println(Thread.currentThread().getName()
175: + " doing GC");
176: System.gc();
177: }
178:
179: }
180: }
181:
182: private class AddNew extends Base {
183: void work() {
184: Object newArray = new Object[] {};
185: ArrayManager.getObject(newArray);
186: ArrayManager.register(newArray, new FakeTCObject());
187:
188: for (int i = 0; i < 10; i++) {
189: // this strange test should make it impossible for the runtime to eliminate this code
190: if (hashCode() == System.currentTimeMillis()) {
191: System.out.println("BONK -- This is harmless ;-)");
192: }
193: }
194:
195: }
196: }
197:
198: private static class FakeTCObject implements TCObject {
199:
200: public boolean autoLockingDisabled() {
201: throw new ImplementMe();
202: }
203:
204: public void booleanFieldChanged(String classname,
205: String fieldname, boolean newValue, int index) {
206: throw new ImplementMe();
207: }
208:
209: public void byteFieldChanged(String classname,
210: String fieldname, byte newValue, int index) {
211: throw new ImplementMe();
212: }
213:
214: public void charFieldChanged(String classname,
215: String fieldname, char newValue, int index) {
216: throw new ImplementMe();
217: }
218:
219: public void clearReference(String fieldName) {
220: throw new ImplementMe();
221: }
222:
223: public int clearReferences(int toClear) {
224: throw new ImplementMe();
225: }
226:
227: public boolean dehydrateIfNew(DNAWriter writer)
228: throws DNAException {
229: throw new ImplementMe();
230: }
231:
232: public void disableAutoLocking() {
233: throw new ImplementMe();
234: }
235:
236: public void doubleFieldChanged(String classname,
237: String fieldname, double newValue, int index) {
238: throw new ImplementMe();
239: }
240:
241: public void floatFieldChanged(String classname,
242: String fieldname, float newValue, int index) {
243: throw new ImplementMe();
244: }
245:
246: public String getFieldNameByOffset(long fieldOffset) {
247: throw new ImplementMe();
248: }
249:
250: public TLinkable getNext() {
251: throw new ImplementMe();
252: }
253:
254: public ObjectID getObjectID() {
255: throw new ImplementMe();
256: }
257:
258: public Object getPeerObject() {
259: throw new ImplementMe();
260: }
261:
262: public TLinkable getPrevious() {
263: throw new ImplementMe();
264: }
265:
266: public Object getResolveLock() {
267: throw new ImplementMe();
268: }
269:
270: public TCClass getTCClass() {
271: throw new ImplementMe();
272: }
273:
274: public long getVersion() {
275: throw new ImplementMe();
276: }
277:
278: public void hydrate(DNA from, boolean force)
279: throws DNAException {
280: throw new ImplementMe();
281: }
282:
283: public void intFieldChanged(String classname, String fieldname,
284: int newValue, int index) {
285: throw new ImplementMe();
286: }
287:
288: public boolean isNew() {
289: throw new ImplementMe();
290: }
291:
292: public boolean isShared() {
293: throw new ImplementMe();
294: }
295:
296: public void logicalInvoke(int method, String methodSignature,
297: Object[] params) {
298: throw new ImplementMe();
299: }
300:
301: public void longFieldChanged(String classname,
302: String fieldname, long newValue, int index) {
303: throw new ImplementMe();
304: }
305:
306: public void objectFieldChanged(String classname,
307: String fieldname, Object newValue, int index) {
308: throw new ImplementMe();
309: }
310:
311: public void objectFieldChangedByOffset(String classname,
312: long fieldOffset, Object newValue, int index) {
313: throw new ImplementMe();
314: }
315:
316: public void resolveAllReferences() {
317: throw new ImplementMe();
318: }
319:
320: public void resolveArrayReference(int index) {
321: throw new ImplementMe();
322: }
323:
324: public void resolveReference(String fieldName) {
325: throw new ImplementMe();
326: }
327:
328: public void setIsNew() {
329: throw new ImplementMe();
330: }
331:
332: public void setNext(TLinkable link) {
333: throw new ImplementMe();
334: }
335:
336: public void setPrevious(TLinkable link) {
337: throw new ImplementMe();
338: }
339:
340: public ObjectID setReference(String fieldName, ObjectID id) {
341: throw new ImplementMe();
342: }
343:
344: public void setArrayReference(int index, ObjectID id) {
345: throw new ImplementMe();
346: }
347:
348: public void setValue(String fieldName, Object obj) {
349: throw new ImplementMe();
350: }
351:
352: public void setVersion(long version) {
353: throw new ImplementMe();
354: }
355:
356: public void shortFieldChanged(String classname,
357: String fieldname, short newValue, int index) {
358: throw new ImplementMe();
359: }
360:
361: public boolean canEvict() {
362: throw new ImplementMe();
363: }
364:
365: public void clearAccessed() {
366: throw new ImplementMe();
367: }
368:
369: public void markAccessed() {
370: throw new ImplementMe();
371: }
372:
373: public boolean recentlyAccessed() {
374: throw new ImplementMe();
375: }
376:
377: public void objectArrayChanged(int startPos, Object[] array,
378: int length) {
379: throw new ImplementMe();
380: }
381:
382: public void primitiveArrayChanged(int startPos, Object array,
383: int length) {
384: throw new ImplementMe();
385: }
386:
387: public int accessCount(int factor) {
388: throw new ImplementMe();
389: }
390:
391: public void literalValueChanged(Object newValue, Object oldValue) {
392: throw new ImplementMe();
393: }
394:
395: public void setLiteralValue(Object newValue) {
396: throw new ImplementMe();
397: }
398:
399: public ArrayIndexOutOfBoundsException checkArrayIndex(int index) {
400: throw new ImplementMe();
401: }
402:
403: public boolean isFieldPortableByOffset(long fieldOffset) {
404: throw new ImplementMe();
405: }
406:
407: }
408:
409: }
|