From 3e02583a7555ccca39b5d8fe2bb3c929105ff439 Mon Sep 17 00:00:00 2001 From: "beard%netscape.com" Date: Mon, 12 Mar 2001 15:35:55 +0000 Subject: [PATCH] [not part of build] Tests simultatenous writing of two cache entries which collide (same hash code). --- netwerk/test/TestCacheCollisions.js | 298 ++++++++++++++++++++++++++++ 1 file changed, 298 insertions(+) create mode 100644 netwerk/test/TestCacheCollisions.js diff --git a/netwerk/test/TestCacheCollisions.js b/netwerk/test/TestCacheCollisions.js new file mode 100644 index 00000000000..242ab869772 --- /dev/null +++ b/netwerk/test/TestCacheCollisions.js @@ -0,0 +1,298 @@ +var DEBUG = true; + +var clientID = "HTTP"; +var nsICache = Components.interfaces.nsICache; + +function getEventQueue() +{ + var nsIEventQueueService = Components.interfaces.nsIEventQueueService; + var CID = Components.classes["@mozilla.org/event-queue-service;1"]; + var service = CID.getService(nsIEventQueueService); + service.createThreadEventQueue(); + return service.getSpecialEventQueue(nsIEventQueueService.CURRENT_THREAD_EVENT_QUEUE); +} + +var eventQueue = getEventQueue(); + +function getCacheService() +{ + var nsCacheService = Components.classes["@mozilla.org/network/cache-service;1"]; + var service = nsCacheService.getService(Components.interfaces.nsICacheService); + return service; +} + +function createCacheSession(clientID, storagePolicy, streamable) +{ + var service = getCacheService(); + var session = service.createSession(clientID, storagePolicy, streamable); + return session; +} + +function openCacheEntry(url, mode) +{ + var session = createCacheSession(clientID, nsICache.STORE_ON_DISK, true); + var entry = session.openCacheEntry(url, mode); + return entry; +} + +function dumpLeaks() +{ + var leakDetector = Components.classes["@mozilla.org/xpcom/leakdetector;1"].getService(Components.interfaces.nsILeakDetector); + leakDetector.dumpLeaks(); +} + +function wrapInputStream(input) +{ + var nsIScriptableInputStream = Components.interfaces.nsIScriptableInputStream; + var factory = Components.classes["@mozilla.org/scriptableinputstream;1"]; + var wrapper = factory.createInstance(nsIScriptableInputStream); + wrapper.init(input); + return wrapper; +} + +function download(key) +{ + var url = new java.net.URL(key); + var data = ""; + var buffer = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, 65536); + var stream = url.openStream(); + while (true) { + var count = stream.read(buffer); + if (count <= 0) + break; + var str = new java.lang.String(buffer, 0, count); + data += str; + } + stream.close(); + return data; +} + +function write(url, data) +{ + var key = url.toString(); + var outputEntry = openCacheEntry(key, nsICache.ACCESS_WRITE); + var output = outputEntry.transport.openOutputStream(0, -1, 0); + var count = output.write(data, data.length); + + // store some metadata. + outputEntry.setMetaDataElement("size", data.length); + + output.close(); + outputEntry.markValid(); + outputEntry.close(); + + return count; +} + +function CacheListener() +{ + this.done = false; +} + +CacheListener.prototype = { + QueryInterface : function(iid) + { + if (iid.equals(Components.interfaces.nsICacheListener)) + return this; + throw Components.results.NS_NOINTERFACE; + }, + + onCacheEntryAvailable : function(/* in nsICacheEntryDescriptor */ descriptor, + /* in nsCacheAccessMode */ accessGranted, + /* in nsresult */ status) + { + this.descriptor = descriptor; + this.status = status; + this.done = true; + } +}; + +function asyncOpenCacheEntry(url, mode) +{ + var session = createCacheSession(clientID, nsICache.STORE_ON_DISK, true); + var listener = new CacheListener(); + session.asyncOpenCacheEntry(url, mode, listener); + while (!listener.done) + eventQueue.processPendingEvents(); + return listener.descriptor; +} + +function asyncWrite(key, data) +{ + var outputEntry = asyncOpenCacheEntry(key, nsICache.ACCESS_WRITE); + + var output = outputEntry.transport.openOutputStream(0, -1, 0); + var count = output.write(data, data.length); + + // store some metadata. + outputEntry.setMetaDataElement("size", data.length); + + output.close(); + outputEntry.markValid(); + outputEntry.close(); + + return count; +} + +function StreamListener() +{ + this.done = false; + this.data = ""; + this.wrapper = null; +} + +StreamListener.prototype = { + QueryInterface : function(iid) + { + if (iid.equals(Components.interfaces.nsIStreamListener) || + iid.equals(Components.interfaces.nsIStreamObserver)) + return this; + throw Components.results.NS_NOINTERFACE; + }, + + onStartRequest : function(request, context) + { + }, + + onStopRequest : function(request, context, statusCode, statusText) + { + this.statusCode = statusCode; + this.done = true; + }, + + onDataAvailable : function(request, context, input, offset, count) + { + if (this.wrapper == null) + this.wrapper = wrapInputStream(input); + input = this.wrapper; + this.data += input.read(count); + } +}; + +function asyncRead(key) +{ + var inputEntry = asyncOpenCacheEntry(key, nsICache.ACCESS_READ); + var listener = new StreamListener(); + inputEntry.transport.asyncRead(listener, null, 0, inputEntry.dataSize, 0); + while (!listener.done) + eventQueue.processPendingEvents(); + inputEntry.close(); + return listener.data; +} + +function read(key) +{ + var inputEntry = openCacheEntry(key, nsICache.ACCESS_READ); + var input = wrapInputStream(inputEntry.transport.openInputStream(0, -1, 0)); + var data = input.read(input.available()); + input.close(); + inputEntry.close(); + return data; +} + +function readMetaData(key, element) +{ + var inputEntry = openCacheEntry(key, nsICache.ACCESS_READ); + var metadata = inputEntry.getMetaDataElement(element); + inputEntry.close(); + return metadata; +} + +function doom(url) +{ + var key = url.toString(); + var doomedEntry = openCacheEntry(key, nsICache.ACCESS_READ_WRITE); + doomedEntry.doom(); + doomedEntry.close(); +} + +// two keys which are known to collide right now. +var key1 = "http://a772.g.akamai.net/7/772/51/7648437e551b56/www.apple.com/t/2001/us/en/i/2.gif"; +var key2 = "http://a772.g.akamai.net/7/772/51/70601300d0bde6/www.apple.com/t/2001/us/en/i/1right.gif"; + +function test() +{ + // 1. generate a collision, and close the colliding entry first. + var entry1 = asyncOpenCacheEntry(key1, nsICache.ACCESS_READ_WRITE); + var data1 = key1; + entry1.setMetaDataElement("size", data1.length); + entry1.markValid(); + var output1 = entry1.transport.openOutputStream(0, -1, 0); + output1.write(data1, data1.length); + + var entry2 = asyncOpenCacheEntry(key2, nsICache.ACCESS_READ_WRITE); + var data2 = key2; + entry2.setMetaDataElement("size", data2.length); + entry2.markValid(); + var output2 = entry2.transport.openOutputStream(0, -1, 0); + output2.write(data2, data2.length); + + output1.close(); + output2.close(); + + entry1.close(); + entry2.close(); +} + +function median(array) +{ + var cmp = function(x, y) { return x - y; } + array.sort(cmp); + var middle = Math.floor(array.length / 2); + return array[middle]; +} + +function sum(array) +{ + var s = 0; + var len = array.length; + for (var i = 0; i < len; ++i) + s += array[i]; + return s; +} + +function time() +{ + var N = 50; + var System = java.lang.System; + var url = new java.net.URL("http://www.mozilla.org"); + var key = url.toString(); + var downloadTimes = new Array(); + for (var i = 0; i < N; ++i) { + var begin = System.currentTimeMillis(); + download(url); + var end = System.currentTimeMillis(); + downloadTimes.push(end - begin); + } + var downloadTotal = sum(downloadTimes); + var downloadMean = downloadTotal / N; + var downloadMedian = median(downloadTimes); + print("" + N + " downloads took " + downloadTotal + " milliseconds."); + print("mean = " + downloadMean + " milliseconds."); + print("median = " + downloadMedian + " milliseconds."); + + var readTimes = new Array(); + for (var i = 0; i < N; ++i) { + var begin = System.currentTimeMillis(); + asyncRead(key); + var end = System.currentTimeMillis(); + readTimes.push(end - begin); + } + var readTotal = sum(readTimes); + var readMean = readTotal / N; + var readMedian = median(readTimes); + print("" + N + " reads took " + readTotal + " milliseconds."); + print("mean = " + readMean + " milliseconds."); + print("median = " + readMedian + " milliseconds."); +} + +// load the cache service before doing anything with Java... +getCacheService(); + +if (DEBUG) { + print("cache service loaded."); +} else { + print("running disk cache test."); + test(); + print("disk cache test complete."); +}