Esempio n. 1
0
 @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;
 }
Esempio n. 2
0
 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();
   }
 }
Esempio n. 5
0
 @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)};
 }
Esempio n. 6
0
 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;
 }
Esempio n. 12
0
 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;
 }
Esempio n. 14
0
  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;
   }
 }
Esempio n. 16
0
 @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;
 }
Esempio n. 17
0
  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);
 }
Esempio n. 22
0
  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);
 }
Esempio n. 24
0
  /**
   * 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;
  }
Esempio n. 26
0
  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;
      }
    }
  }