@Override public KeyListener makeKeyListener( ObjectContainer container, ClientContext context, boolean onStartup) { if (persistent) { container.activate(key, 5); container.activate(parent, 1); container.activate(ctx, 1); } synchronized (this) { if (finished) return null; if (cancelled) return null; } if (key == null) { Logger.error( this, "Key is null - left over BSSF? on " + this + " in makeKeyListener()", new Exception("error")); if (persistent) container.delete(this); return null; } Key newKey = key.getNodeKey(true); if (parent == null) { Logger.error( this, "Parent is null on " + this + " persistent=" + persistent + " key=" + key + " ctx=" + ctx); if (container != null) Logger.error( this, "Stored = " + container.ext().isStored(this) + " active = " + container.ext().isActive(this)); return null; } short prio = parent.getPriorityClass(); KeyListener ret = new SingleKeyListener(newKey, this, prio, persistent, realTimeFlag); if (persistent) { container.deactivate(key, 5); container.deactivate(parent, 1); container.deactivate(ctx, 1); } return ret; }
public boolean objectCanUpdate(ObjectContainer container) { if (!container.ext().isActive(this)) { Logger.error(this, "Updating but not active!", new Exception("error")); return false; } return true; }
public void schedule(ObjectContainer container, ClientContext context) throws InsertException { synchronized (this) { if (finished) { if (logMINOR) Logger.minor(this, "Finished already: " + this); return; } } if (getCHKOnly) { boolean deactivateCB = false; if (persistent) { deactivateCB = !container.ext().isActive(cb); if (deactivateCB) container.activate(cb, 1); container.activate(parent, 1); } ClientKeyBlock block = encode(container, context, true); cb.onEncode(block.getClientKey(), this, container, context); parent.completedBlock(false, container, context); cb.onSuccess(this, container, context); finished = true; if (persistent) { container.store(this); if (deactivateCB) container.deactivate(cb, 1); } } else { getScheduler(context).registerInsert(this, persistent, true, container); } }
/** @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String oidStr = request.getParameter("oid"); if (oidStr == null || oidStr.trim().isEmpty()) throw new ServletException("unexpected request"); Long oid = Long.valueOf(request.getParameter("oid").trim()); // accessDb4o ObjectContainer db = Db4oEmbedded.openFile(Db4oEmbedded.newConfiguration(), ActionManager.DB4OFILENAME); try { TIISubmission sub = db.ext().getByID(oid); db.activate(sub, 10); if (sub == null) response.sendRedirect(ActionManager.getErrorCallbackURL(9999, "oid not found")); response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.write( "<HTML>" + "<HEAD>" + "<TITLE>Dummy Originality Report</TITLE>" + "</HEAD>" + "<BODY>" + "<h2>Originality Report of OID: " + oid + "</h2>" + "<p>Score: " + sub.getReportScore() + "</p>" + "</BODY>" + "</HTML>"); out.close(); } finally { db.close(); } }
@Override public Key[] listKeys(ObjectContainer container) { if (container != null && !persistent) Logger.error( this, "listKeys() on " + this + " but persistent=false, stored is " + container.ext().isStored(this) + " active is " + container.ext().isActive(this)); synchronized (this) { if (cancelled || finished) return new Key[0]; } if (persistent) container.activate(key, 5); return new Key[] {key.getNodeKey(true)}; }
private void innerCheckCachedCooldownData(ObjectContainer container) { boolean active = true; if (persistent) { active = container.ext().isActive(ctx); container.activate(ctx, 1); } cachedCooldownTries = ctx.getCooldownRetries(); cachedCooldownTime = ctx.getCooldownTime(); if (!active) container.deactivate(ctx, 1); }
@Override public boolean forkOnCacheable(ObjectContainer container) { boolean deactivate = false; if (persistent) { deactivate = !container.ext().isActive(ctx); if (deactivate) container.activate(ctx, 1); } boolean retval = ctx.forkOnCacheable; if (deactivate) container.deactivate(ctx, 1); return retval; }
@Override public void preRegister(ObjectContainer container, ClientContext context, boolean toNetwork) { if (!toNetwork) return; boolean deactivate = false; if (persistent) { deactivate = !container.ext().isActive(parent); container.activate(parent, 1); } parent.toNetwork(container, context); if (deactivate) container.deactivate(parent, 1); }
@Override public Key[] listKeys(ObjectContainer container) { boolean activated = false; if (persistent) { activated = container.ext().isActive(segment); if (!activated) container.activate(segment, 1); } Key[] keys = segment.listKeys(container); if (persistent && !activated) container.deactivate(segment, 1); return keys; }
@Override public boolean canWriteClientCache(ObjectContainer container) { boolean deactivate = false; if (persistent) { deactivate = !container.ext().isActive(ctx); if (deactivate) container.activate(ctx, 1); } boolean retval = ctx.canWriteClientCache; if (deactivate) container.deactivate(ctx, 1); return retval; }
@Override public boolean localRequestOnly(ObjectContainer container) { boolean deactivate = false; if (persistent) { deactivate = !container.ext().isActive(ctx); if (deactivate) container.activate(ctx, 1); } boolean retval = ctx.localRequestOnly; if (deactivate) container.deactivate(ctx, 1); return retval; }
private static void activationJustWorks() { // #example: Configure transparent persistence final EmbeddedConfiguration configuration = Db4oEmbedded.newConfiguration(); configuration .common() .add(new TransparentPersistenceSupport(new DeactivatingRollbackStrategy())); ObjectContainer container = Db4oEmbedded.openFile(configuration, DATABASE_FILE_NAME); // #end example try { // #example: Transparent persistence manages activation Driver driver = queryForDriver(container); // Transparent persistence will activate objects as needed System.out.println("Is activated? " + container.ext().isActive(driver)); String nameOfDriver = driver.getName(); System.out.println("The name is " + nameOfDriver); System.out.println("Is activated? " + container.ext().isActive(driver)); // #end example } finally { container.close(); } }
@Override public FetchContext getContext(ObjectContainer container) { boolean segmentActive = true; if (persistent) { segmentActive = container.ext().isActive(segment); if (!segmentActive) container.activate(segment, 1); } FetchContext ctx = segment.blockFetchContext; if (!segmentActive) container.deactivate(segment, 1); if (persistent) container.activate(ctx, 1); return ctx; }
public void test() { Test.store(new Parent1(new Child1())); ObjectContainer container = Test.reOpen(); container .ext() .configure() .addAlias(new TypeAlias("com.db4o.test.aliases.Parent1", "com.db4o.test.aliases.Parent2")); container .ext() .configure() .addAlias(new TypeAlias("com.db4o.test.aliases.Child1", "com.db4o.test.aliases.Child2")); ObjectSet os = container.query(Parent2.class); Test.ensure(os.size() > 0); Parent2 p2 = (Parent2) os.next(); Test.ensure(p2.child != null); }
private BlockItem getBlockItem(ObjectContainer container, ClientContext context) { try { synchronized (this) { if (finished) return null; } if (persistent) { if (sourceData == null) { Logger.error( this, "getBlockItem(): sourceData = null but active = " + container.ext().isActive(this)); return null; } } boolean deactivateBucket = false; if (persistent) { container.activate(uri, 1); deactivateBucket = !container.ext().isActive(sourceData); if (deactivateBucket) container.activate(sourceData, 1); } Bucket data = sourceData.createShadow(); FreenetURI u = uri; if (u.getKeyType().equals("CHK") && !persistent) u = FreenetURI.EMPTY_CHK_URI; else u = u.clone(); if (data == null) { data = context.tempBucketFactory.makeBucket(sourceData.size()); BucketTools.copy(sourceData, data); } if (persistent) { if (deactivateBucket) container.deactivate(sourceData, 1); container.deactivate(uri, 1); } return new BlockItem( this, data, isMetadata, compressionCodec, sourceLength, u, hashCode(), persistent); } catch (IOException e) { fail(new InsertException(InsertException.BUCKET_ERROR, e, null), container, context); return null; } }
@Override public boolean preRegister(ObjectContainer container, ClientContext context, boolean toNetwork) { if (!toNetwork) return false; boolean deactivate = false; if (persistent) { deactivate = !container.ext().isActive(ctx); container.activate(ctx, 1); } boolean localOnly = ctx.localRequestOnly; if (deactivate) container.deactivate(ctx, 1); if (localOnly) { notFoundInStore(container, context); return true; } deactivate = false; if (persistent) { deactivate = !container.ext().isActive(parent); container.activate(parent, 1); } parent.toNetwork(container, context); if (deactivate) container.deactivate(parent, 1); return false; }
public static void main(String[] args) { ObjectContainer container = Db4oEmbedded.openFile("database.db4o"); try { // #example: Freespace size info long freeSpaceSize = container.ext().systemInfo().freespaceSize(); System.out.println("Freespace in bytes: " + freeSpaceSize); // #end example // #example: Freespace entry count info int freeSpaceEntries = container.ext().systemInfo().freespaceEntryCount(); System.out.println("Freespace-entries count: " + freeSpaceEntries); // #end example // #example: Database size info long databaseSize = container.ext().systemInfo().totalSize(); System.out.println("Database size: " + databaseSize); // #end example } finally { container.close(); } }
@Override public long getCooldownWakeupByKey(Key key, ObjectContainer container, ClientContext context) { /* Only deactivate if was deactivated in the first place. * See the removePendingKey() stack trace: Segment is the listener (getter) ! */ boolean activated = false; if (persistent) { activated = container.ext().isActive(segment); if (!activated) container.activate(segment, 1); } long ret = segment.getCooldownWakeupByKey(key, container, context); if (persistent) { if (!activated) container.deactivate(segment, 1); } return ret; }
public boolean isStorageBroken(ObjectContainer container) { if (!container.ext().isActive(this)) throw new IllegalStateException("Must be activated first!"); if (segment == null) { Logger.error(this, "No segment"); return true; } if (ctx == null) { Logger.error(this, "No fetch context"); return true; } if (blockNums == null) { Logger.error(this, "No block nums"); return true; } return false; }
public void removeFrom(ObjectContainer container, ClientContext context) { if (logMINOR) Logger.minor(this, "removeFrom() on " + this); container.activate(uri, 5); uri.removeFrom(container); if (resultingURI != null) { container.activate(resultingURI, 5); resultingURI.removeFrom(container); } // cb, parent are responsible for removing themselves // ctx is passed in and unmodified - usually the ClientPutter removes it container.activate(errors, 5); errors.removeFrom(container); if (freeData && sourceData != null && container.ext().isStored(sourceData)) { Logger.error(this, "Data not removed!"); container.activate(sourceData, 1); sourceData.removeFrom(container); } container.delete(this); }
public void cancel(ObjectContainer container, ClientContext context) { synchronized (this) { if (finished) return; finished = true; } boolean wasActive = true; if (persistent) { container.store(this); wasActive = container.ext().isActive(cb); if (!wasActive) container.activate(cb, 1); container.activate(sourceData, 1); } if (freeData) { sourceData.free(); if (persistent) sourceData.removeFrom(container); sourceData = null; if (persistent) container.store(this); } super.unregister(container, context, getPriorityClass(container)); cb.onFailure(new InsertException(InsertException.CANCELLED), this, container, context); if (!wasActive) container.deactivate(cb, 1); }
public void test() { ObjectContainer con = Test.objectContainer(); Test.deleteAllInstances(this); IsStored isStored = new IsStored(); isStored.myString = "isStored"; con.store(isStored); Test.ensure(con.ext().isStored(isStored)); Test.ensure(Test.occurrences(this) == 1); con.delete(isStored); Test.ensure(!con.ext().isStored(isStored)); Test.ensure(Test.occurrences(this) == 0); con.commit(); if (con.ext().isStored(isStored)) { // this will fail in CS due to locally cached references if (!Test.clientServer) { Test.error(); } } Test.ensure(Test.occurrences(this) == 0); con.store(isStored); Test.ensure(con.ext().isStored(isStored)); Test.ensure(Test.occurrences(this) == 1); con.commit(); Test.ensure(con.ext().isStored(isStored)); Test.ensure(Test.occurrences(this) == 1); con.delete(isStored); Test.ensure(!con.ext().isStored(isStored)); Test.ensure(Test.occurrences(this) == 0); con.commit(); if (con.ext().isStored(isStored)) { // this will fail in CS due to locally cached references if (!Test.clientServer) { Test.error(); } } Test.ensure(Test.occurrences(this) == 0); }
@Override public void removeRunningRequest(SendableRequest request, ObjectContainer container) { synchronized (starterQueue) { for (int i = 0; i < runningPersistentRequests.size(); i++) { if (runningPersistentRequests.get(i) == request) { runningPersistentRequests.remove(i); i--; if (logMINOR) Logger.minor( this, "Removed running request " + request + " size now " + runningPersistentRequests.size()); } } } // We *DO* need to call clearCooldown here because it only becomes runnable for persistent // requests after it has been removed from starterQueue. boolean active = container.ext().isActive(request); if (!active) container.activate(request, 1); request.clearCooldown(container, clientContext, false); if (!active) container.deactivate(request, 1); }
/** * ATTENTION: This function is duplicated in the Web Of Trust plugin, please backport any changes. */ private synchronized void defragmentDatabase(File databaseFile) throws IOException { Logger.normal(this, "Defragmenting database ..."); if (db != null) throw new RuntimeException("Database is opened already!"); if (mPluginRespirator == null) { Logger.normal( this, "No PluginRespirator found, probably running as unit test, not defragmenting."); return; } final Random random = mPluginRespirator.getNode().fastWeakRandom; // Open it first, because defrag will throw if it needs to upgrade the file. { final ObjectContainer database = Db4o.openFile(getNewDatabaseConfiguration(), databaseFile.getAbsolutePath()); // Db4o will throw during defragmentation if new fields were added to classes and we didn't // initialize their values on existing // objects before defragmenting. So we just don't defragment if the database format version // has changed. final boolean canDefragment = Configuration.peekDatabaseFormatVersion(this, database.ext()) == Freetalk.DATABASE_FORMAT_VERSION; while (!database.close()) ; if (!canDefragment) { Logger.normal(this, "Not defragmenting, database format version changed!"); return; } if (!databaseFile.exists()) { Logger.error( this, "Database file does not exist after openFile: " + databaseFile.getAbsolutePath()); return; } } final File backupFile = new File(databaseFile.getAbsolutePath() + ".backup"); if (backupFile.exists()) { Logger.error( this, "Not defragmenting database: Backup file exists, maybe the node was shot during defrag: " + backupFile.getAbsolutePath()); return; } final File tmpFile = new File(databaseFile.getAbsolutePath() + ".temp"); FileUtil.secureDelete(tmpFile); /* As opposed to the default, BTreeIDMapping uses an on-disk file instead of in-memory for mapping IDs. /* Reduces memory usage during defragmentation while being slower. /* However as of db4o 7.4.63.11890, it is bugged and prevents defragmentation from succeeding for my database, so we don't use it for now. */ final DefragmentConfig config = new DefragmentConfig( databaseFile.getAbsolutePath(), backupFile.getAbsolutePath() // ,new BTreeIDMapping(tmpFile.getAbsolutePath()) ); /* Delete classes which are not known to the classloader anymore - We do NOT do this because: /* - It is buggy and causes exceptions often as of db4o 7.4.63.11890 /* - Freetalk has always had proper database upgrade code (function upgradeDB()) and does not rely on automatic schema evolution. /* If we need to get rid of certain objects we should do it in the database upgrade code, */ // config.storedClassFilter(new AvailableClassFilter()); config.db4oConfig(getNewDatabaseConfiguration()); try { Defragment.defrag(config); } catch (Exception e) { Logger.error(this, "Defragment failed", e); try { restoreDatabaseBackup(databaseFile, backupFile); return; } catch (IOException e2) { Logger.error(this, "Unable to restore backup", e2); throw new IOException(e); } } final long oldSize = backupFile.length(); final long newSize = databaseFile.length(); if (newSize <= 0) { Logger.error(this, "Defrag produced an empty file! Trying to restore old database file..."); databaseFile.delete(); try { restoreDatabaseBackup(databaseFile, backupFile); } catch (IOException e2) { Logger.error(this, "Unable to restore backup", e2); throw new IOException(e2); } } else { final double change = 100.0 * (((double) (oldSize - newSize)) / ((double) oldSize)); FileUtil.secureDelete(tmpFile, random); FileUtil.secureDelete(backupFile, random); Logger.normal( this, "Defragment completed. " + SizeUtil.formatSize(oldSize) + " (" + oldSize + ") -> " + SizeUtil.formatSize(newSize) + " (" + newSize + ") (" + (int) change + "% shrink)"); } }
public Object removeKeyBefore( final long now, long dontCareAfterMillis, ObjectContainer container, int maxCount, PersistentCooldownQueue altQueue) { // Will be called repeatedly until no more keys are returned, so it doesn't // matter very much if they're not in order. // This query returns bogus results (cooldown items with times in the future). // ObjectSet results = container.query(new Predicate() { // public boolean match(PersistentCooldownQueueItem persistentCooldownQueueItem) { // if(persistentCooldownQueueItem.time >= now) return false; // if(persistentCooldownQueueItem.parent != PersistentCooldownQueue.this) return false; // return true; // } // }); ArrayList<Key> v = null; if (!itemsFromLastTime.isEmpty()) { if (v == null) v = new ArrayList<Key>(Math.min(maxCount, itemsFromLastTime.size())); Logger.normal( this, "Overflow handling in cooldown queue: reusing items from last time, now " + itemsFromLastTime.size()); for (Iterator<PersistentCooldownQueueItem> it = itemsFromLastTime.iterator(); it.hasNext() && v.size() < maxCount; ) { PersistentCooldownQueueItem i = it.next(); container.activate(i, 1); if (i.parent != this && i.parent != altQueue) { container.deactivate(i, 1); continue; } if (i.time >= now) { container.deactivate(i, 1); if (v.isEmpty()) return i.time; return v.toArray(new Key[v.size()]); } container.activate(i.key, 5); if (i.client == null || !container.ext().isStored(i.client)) { Logger.normal( this, "Client has been removed but not the persistent cooldown queue item: time " + i.time + " for key " + i.key); } if (i.key == null) { Logger.error( this, "Key is null on cooldown queue! i = " + i + " client=" + i.client + " key as bytes = " + i.keyAsBytes); } else { v.add(i.key.cloneKey()); i.key.removeFrom(container); } i.delete(container); it.remove(); } } if (v != null && v.size() == maxCount) return v.toArray(new Key[v.size()]); // Lets re-code it in SODA. long tStart = System.currentTimeMillis(); Query query = container.query(); query.constrain(PersistentCooldownQueueItem.class); // Don't constrain on parent. // parent index is humongous, so we get a huge memory spike, queries take ages. // Just check manually. query .descend("time") .orderAscending() .constrain(Long.valueOf(now + dontCareAfterMillis)) .smaller(); ObjectSet<PersistentCooldownQueueItem> results = query.execute(); if (results.hasNext()) { long tEnd = System.currentTimeMillis(); if (tEnd - tStart > 1000) Logger.error(this, "Query took " + (tEnd - tStart) + " for " + results.size()); else if (logMINOR) Logger.minor(this, "Query took " + (tEnd - tStart)); if (v == null) v = new ArrayList<Key>(Math.min(maxCount, results.size())); while (results.hasNext() && v.size() < maxCount) { PersistentCooldownQueueItem i = (PersistentCooldownQueueItem) results.next(); if (i.parent != this && i.parent != altQueue) { continue; } if (i.time >= now) { if (v.isEmpty()) return i.time; break; } container.activate(i.key, 5); if (i.client == null || !container.ext().isStored(i.client)) { Logger.normal( this, "Client has been removed but not the persistent cooldown queue item: time " + i.time + " for key " + i.key); } if (i.key == null) { Logger.error( this, "Key is null on cooldown queue! i = " + i + " client=" + i.client + " key as bytes = " + i.keyAsBytes); } else { v.add(i.key.cloneKey()); i.key.removeFrom(container); } i.delete(container); } if (!v.isEmpty()) { while (results.hasNext() && itemsFromLastTime.size() < KEEP_ITEMS_FROM_LAST_TIME) { PersistentCooldownQueueItem i = (PersistentCooldownQueueItem) results.next(); container.deactivate(i, 1); itemsFromLastTime.add(i); } Logger.normal( this, "Overflow handling in cooldown queue: added items, items from last time now " + itemsFromLastTime.size()); return v.toArray(new Key[v.size()]); } } else { long tEnd = System.currentTimeMillis(); if (tEnd - tStart > 1000) Logger.error(this, "Query took " + (tEnd - tStart)); else if (logMINOR) Logger.minor(this, "Query took " + (tEnd - tStart)); return null; } return null; }
public void onSuccess(FetchResult result, ClientGetter state, ObjectContainer container) { Logger.minor(this, "Succeeded: " + identifier); Bucket data = result.asBucket(); if (persistenceType == PERSIST_FOREVER) { if (data != null) container.activate(data, 5); if (returnBucket != null) container.activate(returnBucket, 5); container.activate(client, 1); if (tempFile != null) container.activate(tempFile, 5); if (targetFile != null) container.activate(targetFile, 5); } if (returnBucket != data && !binaryBlob) { boolean failed = true; synchronized (this) { if (finished) { Logger.error( this, "Already finished but onSuccess() for " + this + " data = " + data, new Exception("debug")); data.free(); if (persistenceType == PERSIST_FOREVER) data.removeFrom(container); return; // Already failed - bucket error maybe?? } if (returnType == ClientGetMessage.RETURN_TYPE_DIRECT && returnBucket == null) { // Lost bucket for some reason e.g. bucket error (caused by IOException) on previous try?? // Recover... returnBucket = data; failed = false; } } if (failed && persistenceType == PERSIST_FOREVER) { if (container.ext().getID(returnBucket) == container.ext().getID(data)) { Logger.error( this, "DB4O BUG DETECTED WITHOUT ARRAY HANDLING! EVIL HORRIBLE BUG! UID(returnBucket)=" + container.ext().getID(returnBucket) + " for " + returnBucket + " active=" + container.ext().isActive(returnBucket) + " stored = " + container.ext().isStored(returnBucket) + " but UID(data)=" + container.ext().getID(data) + " for " + data + " active = " + container.ext().isActive(data) + " stored = " + container.ext().isStored(data)); // Succeed anyway, hope that the returned bucket is consistent... returnBucket = data; failed = false; } } if (failed) { Logger.error( this, "returnBucket = " + returnBucket + " but onSuccess() data = " + data, new Exception("debug")); // Caller guarantees that data == returnBucket onFailure( new FetchException(FetchException.INTERNAL_ERROR, "Data != returnBucket"), null, container); return; } } boolean dontFree = false; // FIXME I don't think this is a problem in this case...? (Disk write while locked..) AllDataMessage adm = null; synchronized (this) { if (succeeded) { Logger.error(this, "onSuccess called twice for " + this + " (" + identifier + ')'); return; // We might be called twice; ignore it if so. } started = true; if (!binaryBlob) this.foundDataMimeType = result.getMimeType(); else this.foundDataMimeType = BinaryBlob.MIME_TYPE; if (returnType == ClientGetMessage.RETURN_TYPE_DIRECT) { // Send all the data at once // FIXME there should be other options // FIXME: CompletionTime is set on finish() : we need to give it current time here // but it means we won't always return the same value to clients... Does it matter ? adm = new AllDataMessage( returnBucket, identifier, global, startupTime, System.currentTimeMillis(), this.foundDataMimeType); if (persistenceType == PERSIST_CONNECTION) adm.setFreeOnSent(); dontFree = true; /* * } else if(returnType == ClientGetMessage.RETURN_TYPE_NONE) { // Do nothing */ } else if (returnType == ClientGetMessage.RETURN_TYPE_DISK) { // Write to temp file, then rename over filename if (!FileUtil.renameTo(tempFile, targetFile)) { postFetchProtocolErrorMessage = new ProtocolErrorMessage( ProtocolErrorMessage.COULD_NOT_RENAME_FILE, false, null, identifier, global); // Don't delete temp file, user might want it. } returnBucket = new FileBucket(targetFile, false, true, false, false, false); } if (persistenceType == PERSIST_FOREVER && progressPending != null) { container.activate(progressPending, 1); progressPending.removeFrom(container); } progressPending = null; this.foundDataLength = returnBucket.size(); this.succeeded = true; finished = true; } trySendDataFoundOrGetFailed(null, container); if (adm != null) trySendAllDataMessage(adm, null, container); if (!dontFree) { data.free(); } if (persistenceType == PERSIST_FOREVER) { returnBucket.storeTo(container); container.store(this); } finish(container); if (client != null) client.notifySuccess(this, container); }
/** * Compare a recently registered SendableRequest to what is already on the starter queue. If it is * better, kick out stuff from the queue until we are just over the limit. * * @param req * @param container */ public void maybeAddToStarterQueue( SendableRequest req, ObjectContainer container, SendableRequest[] mightBeActive) { short prio = req.getPriorityClass(container); if (logMINOR) Logger.minor(this, "Maybe adding to starter queue: prio=" + prio); synchronized (starterQueue) { boolean betterThanSome = false; int size = 0; PersistentChosenRequest prev = null; for (PersistentChosenRequest old : starterQueue) { if (old.request == req) { // Wait for a reselect. Otherwise we can starve other // requests. Note that this happens with persistent SBI's: // they are added at the new retry count before being // removed at the old retry count. if (logMINOR) Logger.minor(this, "Already on starter queue: " + old + " for " + req); return; } if (prev == old) Logger.error(this, "ON STARTER QUEUE TWICE: " + prev + " for " + prev.request); if (prev != null && prev.request == old.request) Logger.error( this, "REQUEST ON STARTER QUEUE TWICE: " + prev + " for " + prev.request + " vs " + old + " for " + old.request); boolean ignoreActive = false; if (mightBeActive != null) { for (SendableRequest tmp : mightBeActive) if (tmp == old.request) ignoreActive = true; } if (!ignoreActive) { if (container.ext().isActive(old.request)) Logger.warning( this, "REQUEST ALREADY ACTIVATED: " + old.request + " for " + old + " while checking request queue in maybeAddToStarterQueue for " + req); else if (logDEBUG) Logger.debug( this, "Not already activated for " + old + " in while checking request queue in maybeAddToStarterQueue for " + req); } else if (logMINOR) Logger.minor( this, "Ignoring active because just registered: " + old.request + " in maybeAddToStarterQueue for " + req); size += old.sizeNotStarted(); if (old.prio > prio) betterThanSome = true; if (old.request == req) return; prev = old; } if (size >= MAX_STARTER_QUEUE_SIZE && !betterThanSome) { if (logMINOR) Logger.minor( this, "Not adding to starter queue: over limit and req not better than any queued requests"); return; } } addToStarterQueue(req, container); trimStarterQueue(container); }
private void fillRequestStarterQueue(ObjectContainer container, ClientContext context) { synchronized (this) { if (fillingRequestStarterQueue) return; fillingRequestStarterQueue = true; } long now = System.currentTimeMillis(); try { if (logMINOR) Logger.minor( this, "Filling request queue... (SSK=" + isSSKScheduler + " insert=" + isInsertScheduler); long noLaterThan = Long.MAX_VALUE; boolean checkCooldownQueue = now > nextQueueFillRequestStarterQueue; if ((!isInsertScheduler) && checkCooldownQueue) { if (persistentCooldownQueue != null) noLaterThan = moveKeysFromCooldownQueue(persistentCooldownQueue, true, container); noLaterThan = Math.min( noLaterThan, moveKeysFromCooldownQueue(transientCooldownQueue, false, container)); } // If anything has been re-added, the request starter will have been woken up. short fuzz = -1; if (PRIORITY_SOFT.equals(choosenPriorityScheduler)) fuzz = -1; else if (PRIORITY_HARD.equals(choosenPriorityScheduler)) fuzz = 0; boolean added = false; synchronized (starterQueue) { if (logMINOR && (!isSSKScheduler) && (!isInsertScheduler)) { Logger.minor(this, "Scheduling CHK fetches..."); for (SendableRequest req : runningPersistentRequests) { boolean wasActive = container.ext().isActive(req); if (!wasActive) container.activate(req, 1); Logger.minor(this, "Running persistent request: " + req); if (!wasActive) container.deactivate(req, 1); } } // Recompute starterQueueLength int length = 0; PersistentChosenRequest old = null; for (PersistentChosenRequest req : starterQueue) { if (old == req) Logger.error(this, "DUPLICATE CHOSEN REQUESTS ON QUEUE: " + req); if (old != null && old.request == req.request) Logger.error( this, "DUPLICATE REQUEST ON QUEUE: " + old + " vs " + req + " both " + req.request); boolean ignoreActive = false; if (!ignoreActive) { if (container.ext().isActive(req.request)) Logger.warning( this, "REQUEST ALREADY ACTIVATED: " + req.request + " for " + req + " while checking request queue in filling request queue"); else if (logMINOR) Logger.minor( this, "Not already activated for " + req + " in while checking request queue in filling request queue"); } else if (logMINOR) Logger.minor(this, "Ignoring active because just registered: " + req.request); req.pruneDuplicates(ClientRequestScheduler.this); old = req; length += req.sizeNotStarted(); } if (logMINOR) Logger.minor( this, "Queue size: " + length + " SSK=" + isSSKScheduler + " insert=" + isInsertScheduler); if (length > MAX_STARTER_QUEUE_SIZE * 3 / 4) { if (length >= WARNING_STARTER_QUEUE_SIZE) Logger.error(this, "Queue already full: " + length); return; } } if ((!isSSKScheduler) && (!isInsertScheduler)) { Logger.minor(this, "Scheduling CHK fetches..."); } boolean addedMore = false; while (true) { SelectorReturn r; // Must synchronize on scheduler to avoid problems with cooldown queue. See notes on // CooldownTracker.clearCachedWakeup, which also applies to other cooldown operations. synchronized (this) { r = selector.removeFirstInner( fuzz, random, offeredKeys, starter, schedCore, schedTransient, false, true, Short.MAX_VALUE, isRTScheduler, context, container, now); } SendableRequest request = null; if (r != null && r.req != null) request = r.req; else { if (r != null && r.wakeupTime > 0 && noLaterThan > r.wakeupTime) { noLaterThan = r.wakeupTime; if (logMINOR) Logger.minor( this, "Waking up in " + TimeUtil.formatTime(noLaterThan - now) + " for cooldowns"); } } if (request == null) { synchronized (ClientRequestScheduler.this) { // Don't wake up for a while, but no later than the time we expect the next item to come // off the cooldown queue if (checkCooldownQueue && !added) { nextQueueFillRequestStarterQueue = System.currentTimeMillis() + WAIT_AFTER_NOTHING_TO_START; if (nextQueueFillRequestStarterQueue > noLaterThan) nextQueueFillRequestStarterQueue = noLaterThan + 1; } } if (addedMore) starter.wakeUp(); return; } boolean full = addToStarterQueue(request, container); container.deactivate(request, 1); if (!added) starter.wakeUp(); else addedMore = true; added = true; if (full) { if (addedMore) starter.wakeUp(); return; } } } finally { synchronized (this) { fillingRequestStarterQueue = false; } } }