package com.sleepycat.je.cleaner;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.logging.Level;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.dbi.DatabaseId;
import com.sleepycat.je.dbi.DatabaseImpl;
import com.sleepycat.je.dbi.DbTree;
import com.sleepycat.je.dbi.EnvironmentImpl;
import com.sleepycat.je.dbi.MemoryBudget;
import com.sleepycat.je.log.CleanerFileReader;
import com.sleepycat.je.tree.BIN;
import com.sleepycat.je.tree.ChildReference;
import com.sleepycat.je.tree.DIN;
import com.sleepycat.je.tree.IN;
import com.sleepycat.je.tree.LN;
import com.sleepycat.je.tree.SearchResult;
import com.sleepycat.je.tree.Tree;
import com.sleepycat.je.tree.TreeLocation;
import com.sleepycat.je.tree.WithRootLatched;
import com.sleepycat.je.txn.BasicLocker;
import com.sleepycat.je.txn.LockGrantType;
import com.sleepycat.je.txn.LockResult;
import com.sleepycat.je.txn.LockType;
import com.sleepycat.je.utilint.DaemonThread;
import com.sleepycat.je.utilint.DbLsn;
import com.sleepycat.je.utilint.Tracer;
import de.ovgu.cide.jakutil.*;
/** 
 * Reads all entries in a log file and either determines them to be obsolete or
 * marks them for migration. LNs are marked for migration by setting the BIN
 * entry MIGRATE flag. INs are marked for migration by setting the dirty flag.
 * May be invoked explicitly by calling doClean, or woken up if used as a daemon
 * thread.
 */
class FileProcessor extends DaemonThread {
  /** 
 * The number of LN log entries after we process pending LNs. If we do this
 * too seldom, the pending LN queue may grow large, and it isn't budgeted
 * memory. If we process it too often, we will repeatedly request a
 * non-blocking lock for the same locked node.
 */
  private static final int PROCESS_PENDING_EVERY_N_LNS=100;
  /** 
 * Whether to prohibit BINDeltas for a BIN that is fetched by the cleaner.
 * The theory is that when fetching a BIN during cleaning we normally expect
 * that the BIN will be evicted soon, and a delta during checkpoint would be
 * wasted. However, this does not take into account use of the BIN by the
 * application after fetching; the BIN could become hot and then deltas may
 * be profitable. To be safe we currently allow deltas when fetching.
 */
  private static final boolean PROHIBIT_DELTAS_WHEN_FETCHING=false;
  private static final boolean DEBUG_TRACING=false;
  private EnvironmentImpl env;
  private Cleaner cleaner;
  private FileSelector fileSelector;
  private UtilizationProfile profile;
  FileProcessor(  String name,  EnvironmentImpl env,  Cleaner cleaner,  UtilizationProfile profile,  FileSelector fileSelector){
    super(0,name,env);
    this.env=env;
    this.cleaner=cleaner;
    this.fileSelector=fileSelector;
    this.profile=profile;
  }
  public void clearEnv(){
    env=null;
    cleaner=null;
    fileSelector=null;
    profile=null;
  }
  /** 
 * Return the number of retries when a deadlock exception occurs.
 */
  protected int nDeadlockRetries() throws DatabaseException {
    return cleaner.nDeadlockRetries;
  }
  /** 
 * Cleaner doesn't have a work queue so just throw an exception if it's ever
 * called.
 */
  public void addToQueue(  Object o) throws DatabaseException {
    throw new DatabaseException("Cleaner.addToQueue should never be called.");
  }
  /** 
 * Activates the cleaner. Is normally called when je.cleaner.byteInterval
 * bytes are written to the log.
 */
  public void onWakeup() throws DatabaseException {
    doClean(true,true,false);
  }
  /** 
 * Cleans selected files and returns the number of files cleaned. May be
 * called by the daemon thread or programatically.
 * @param invokedFromDaemoncurrently has no effect.
 * @param cleanMultipleFilesis true to clean until we're under budget, or false to clean
 * at most one file.
 * @param forceCleaningis true to clean even if we're not under the utilization
 * threshold.
 * @return the number of files cleaned, not including files cleaned
 * unsuccessfully.
 */
  public synchronized int doClean(  boolean invokedFromDaemon,  boolean cleanMultipleFiles,  boolean forceCleaning) throws DatabaseException {
    if (env.isClosed()) {
      return 0;
    }
    int nOriginalLogFiles=profile.getNumberOfFiles();
    int nFilesCleaned=0;
    while (true) {
      if (nFilesCleaned >= nOriginalLogFiles) {
        break;
      }
      if (env.isClosing()) {
        break;
      }
      cleaner.processPending();
      cleaner.deleteSafeToDeleteFiles();
      boolean needLowUtilizationSet=cleaner.clusterResident || cleaner.clusterAll;
      Long fileNum=fileSelector.selectFileForCleaning(profile,forceCleaning,needLowUtilizationSet,cleaner.maxBatchFiles);
      cleaner.updateReadOnlyFileCollections();
      if (fileNum == null) {
        break;
      }
      this.hook138();
      boolean finished=false;
      long fileNumValue=fileNum.longValue();
      int runId=++cleaner.nCleanerRuns;
      try {
        String traceMsg="CleanerRun " + runId + " on file 0x"+ Long.toHexString(fileNumValue);
        traceMsg=this.hook139(traceMsg);
        this.hook121(traceMsg);
        if (DEBUG_TRACING) {
          System.out.println("\n" + traceMsg);
        }
        if (processFile(fileNum)) {
          fileSelector.addCleanedFile(fileNum);
          nFilesCleaned+=1;
          this.hook140();
          finished=true;
        }
      }
 catch (      IOException IOE) {
        this.hook122(IOE);
        throw new DatabaseException(IOE);
      }
 finally {
        if (!finished) {
          fileSelector.putBackFileForCleaning(fileNum);
        }
        String traceMsg="CleanerRun " + runId + " on file 0x"+ Long.toHexString(fileNumValue)+ " invokedFromDaemon="+ invokedFromDaemon+ " finished="+ finished;
        traceMsg=this.hook141(traceMsg);
        this.hook123(traceMsg);
        if (DEBUG_TRACING) {
          System.out.println("\n" + traceMsg);
        }
      }
      if (!cleanMultipleFiles) {
        break;
      }
    }
    return nFilesCleaned;
  }
  /** 
 * Process all log entries in the given file.
 * Note that we check for obsolete entries using the active TFS
 * (TrackedFileSummary) for a file while it is being processed, and we
 * prohibit flushing (eviction) of that offset information until file
 * processing is complete. An entry could become obsolete because: 1- normal
 * application activity deletes or updates the entry, 2- proactive migration
 * migrates the entry before we process it, or 3- if trackDetail is false.
 * However, checking the TFS is expensive if it has many entries, because we
 * perform a linear search. There is a tradeoff between the cost of the TFS
 * lookup and its benefit, which is to avoid a tree search if the entry is
 * obsolete. Note that many more lookups for non-obsolete entries than
 * obsolete entries will typically be done. In spite of that we check the
 * tracked summary to avoid the situation where eviction does proactive
 * migration, and evicts a BIN that is very soon afterward fetched during
 * cleaning.
 * @return false if we aborted file processing because the environment is
 * being closed.
 */
  private boolean processFile(  Long fileNum) throws DatabaseException, IOException {
    return new FileProcessor_processFile(this,fileNum).execute();
  }
  /** 
 * Processes the first LN in the look ahead cache and removes it from the
 * cache. While the BIN is latched, look through the BIN for other LNs in
 * the cache; if any match, process them to avoid a tree search later.
 * @param info
 * @param offset
 */
  private void processLN(  Long fileNum,  TreeLocation location,  Long offset,  LNInfo info,  Object lookAheadCachep,  Map dbCache) throws DatabaseException {
    new FileProcessor_processLN(this,fileNum,location,offset,info,lookAheadCachep,dbCache).execute();
  }
  /** 
 * Processes an LN that was found in the tree. Lock the LN's node ID and
 * then set the entry's MIGRATE flag if the LSN of the LN log entry is the
 * active LSN in the tree.
 * @param infoidentifies the LN log entry.
 * @param logLsnis the LSN of the log entry.
 * @param treeLsnis the LSN found in the tree.
 * @param binis the BIN found in the tree; is latched on method entry and
 * exit.
 * @param indexis the BIN index found in the tree.
 * @param parentDINis non-null for a DupCountLN only; if non-null, is latched on
 * method entry and exit.
 */
  private void processFoundLN(  LNInfo info,  long logLsn,  long treeLsn,  BIN bin,  int index,  DIN parentDIN) throws DatabaseException {
    LN ln=info.getLN();
    byte[] key=info.getKey();
    byte[] dupKey=info.getDupKey();
    DatabaseImpl db=bin.getDatabase();
    boolean isDupCountLN=parentDIN != null;
    boolean obsolete=false;
    boolean migrated=false;
    boolean lockDenied=false;
    boolean completed=false;
    long nodeId=ln.getNodeId();
    BasicLocker locker=null;
    try {
      Tree tree=db.getTree();
      assert tree != null;
      if (treeLsn != logLsn) {
        locker=new BasicLocker(env);
        LockResult lockRet=locker.nonBlockingLock(nodeId,LockType.READ,db);
        if (lockRet.getLockGrant() == LockGrantType.DENIED) {
          this.hook142();
          lockDenied=true;
        }
 else {
          this.hook143();
          obsolete=true;
        }
      }
      if (!obsolete && !lockDenied) {
        if (isDupCountLN) {
          ChildReference dclRef=parentDIN.getDupCountLNRef();
          dclRef.setMigrate(true);
          parentDIN.setDirty(true);
          if (treeLsn == logLsn && dclRef.getTarget() == null) {
            ln.postFetchInit(db,logLsn);
            parentDIN.updateDupCountLN(ln);
          }
        }
 else {
          bin.setMigrate(index,true);
          bin.setDirty(true);
          if (treeLsn == logLsn && bin.getTarget(index) == null) {
            ln.postFetchInit(db,logLsn);
            bin.updateEntry(index,ln);
          }
          if (PROHIBIT_DELTAS_WHEN_FETCHING && bin.getGeneration() == 0) {
            bin.setProhibitNextDelta();
          }
          bin.setGeneration();
        }
        this.hook144();
        migrated=true;
      }
      completed=true;
    }
  finally {
      if (locker != null) {
        locker.operationEnd();
      }
      if (completed && lockDenied) {
        fileSelector.addPendingLN(ln,db.getId(),key,dupKey);
      }
      this.hook124(logLsn,ln,obsolete,migrated,completed);
    }
  }
  /** 
 * If an IN is still in use in the in-memory tree, dirty it. The checkpoint
 * invoked at the end of the cleaning run will end up rewriting it.
 */
  private void processIN(  IN inClone,  DatabaseImpl db,  long lsn) throws DatabaseException {
    try {
      boolean obsolete=false;
      boolean dirtied=false;
      boolean completed=false;
      this.hook125(inClone,db,lsn,obsolete,dirtied,completed);
    }
 catch (    ReturnVoid r) {
      return;
    }
  }
  /** 
 * Given a clone of an IN that has been taken out of the log, try to find it
 * in the tree and verify that it is the current one in the log. Returns the
 * node in the tree if it is found and it is current re: LSN's. Otherwise
 * returns null if the clone is not found in the tree or it's not the latest
 * version. Caller is responsible for unlatching the returned IN.
 */
  private IN findINInTree(  Tree tree,  DatabaseImpl db,  IN inClone,  long lsn) throws DatabaseException {
    try {
      if (inClone.isDbRoot()) {
        IN rootIN=isRoot(tree,db,inClone,lsn);
        if (rootIN == null) {
          return null;
        }
 else {
          return rootIN;
        }
      }
      inClone.latch(Cleaner.UPDATE_GENERATION);
      SearchResult result=null;
      this.hook134(tree,db,inClone,lsn,result);
      throw ReturnHack.returnObject;
    }
 catch (    ReturnObject r) {
      return (IN)r.value;
    }
  }
private static class RootDoWork implements WithRootLatched {
    private DatabaseImpl db;
    private IN inClone;
    private long lsn;
    RootDoWork(    DatabaseImpl db,    IN inClone,    long lsn){
      this.db=db;
      this.inClone=inClone;
      this.lsn=lsn;
    }
    public IN doWork(    ChildReference root) throws DatabaseException {
      if (root == null || root.fetchTarget(db,null).getNodeId() != inClone.getNodeId()) {
        return null;
      }
      if (DbLsn.compareTo(root.getLsn(),lsn) <= 0) {
        IN rootIN=(IN)root.fetchTarget(db,null);
        rootIN.latch(Cleaner.UPDATE_GENERATION);
        return rootIN;
      }
 else {
        return null;
      }
    }
  }
  /** 
 * Check if the cloned IN is the same node as the root in tree. Return the
 * real root if it is, null otherwise. If non-null is returned, the returned
 * IN (the root) is latched -- caller is responsible for unlatching it.
 */
  private IN isRoot(  Tree tree,  DatabaseImpl db,  IN inClone,  long lsn) throws DatabaseException {
    RootDoWork rdw=new RootDoWork(db,inClone,lsn);
    return tree.withRootLatchedShared(rdw);
  }
  /** 
 * XXX: Was this intended to override Thread.toString()? If so it no longer
 * does, because we separated Thread from DaemonThread.
 */
  public String toString(){
    StringBuffer sb=new StringBuffer();
    sb.append("<Cleaner name=\"").append(name).append("\"/>");
    return sb.toString();
  }
@MethodObject static class FileProcessor_processFile {
    FileProcessor_processFile(    FileProcessor _this,    Long fileNum){
      this._this=_this;
      this.fileNum=fileNum;
    }
    boolean execute() throws DatabaseException, IOException {
      obsoleteOffsets=new PackedOffsets();
      tfs=_this.profile.getObsoleteDetail(fileNum,obsoleteOffsets,true);
      obsoleteIter=obsoleteOffsets.iterator();
      nextObsolete=-1;
      readBufferSize=_this.cleaner.readBufferSize;
      this.hook128();
      this.hook161();
      this.hook119();
      this.hook127();
      this.hook154();
      dbCache=new HashMap();
      try {
        reader=new CleanerFileReader(_this.env,readBufferSize,DbLsn.NULL_LSN,fileNum);
        this.hook137();
        dbMapTree=_this.env.getDbMapTree();
        location=new TreeLocation();
        nProcessedLNs=0;
        while (reader.readNextEntry()) {
          this.hook146();
          lsn=reader.getLastLsn();
          fileOffset=DbLsn.getFileOffset(lsn);
          isLN=reader.isLN();
          isIN=reader.isIN();
          isRoot=reader.isRoot();
          isObsolete=false;
          if (_this.env.isClosing()) {
            return false;
          }
          while (nextObsolete < fileOffset && obsoleteIter.hasNext()) {
            nextObsolete=obsoleteIter.next();
          }
          if (nextObsolete == fileOffset) {
            isObsolete=true;
          }
          if (!isObsolete && !isLN && !isIN&& !isRoot) {
            isObsolete=true;
          }
          if (!isObsolete && isLN && reader.getLN().isDeleted()) {
            isObsolete=true;
          }
          if (!isObsolete && tfs != null && tfs.containsObsoleteOffset(fileOffset)) {
            isObsolete=true;
          }
          if (isObsolete) {
            this.hook147();
            this.hook156();
            continue;
          }
          this.hook120();
          if (isLN) {
            targetLN=reader.getLN();
            dbId2=reader.getDatabaseId();
            key=reader.getKey();
            dupKey=reader.getDupTreeKey();
            aLsn=new Long(DbLsn.getFileOffset(lsn));
            aLninfo=new LNInfo(targetLN,dbId2,key,dupKey);
            this.hook130();
            nProcessedLNs+=1;
            if (nProcessedLNs % _this.PROCESS_PENDING_EVERY_N_LNS == 0) {
              _this.cleaner.processPending();
            }
          }
 else           if (isIN) {
            targetIN=reader.getIN();
            dbId3=reader.getDatabaseId();
            db3=dbMapTree.getDb(dbId3,_this.cleaner.lockTimeout,dbCache);
            targetIN.setDatabase(db3);
            _this.processIN(targetIN,db3,lsn);
          }
 else           if (isRoot) {
            _this.env.rewriteMapTreeRoot(lsn);
          }
 else {
            assert false;
          }
        }
        this.hook129();
        this.hook155();
        this.hook145();
      }
  finally {
        this.hook162();
        if (tfs != null) {
          tfs.setAllowFlush(true);
        }
      }
      return true;
    }
    protected FileProcessor _this;
    protected Long fileNum;
    protected PackedOffsets obsoleteOffsets;
    protected TrackedFileSummary tfs;
    protected PackedOffsets.Iterator obsoleteIter;
    protected long nextObsolete;
    protected int readBufferSize;
    protected int lookAheadCacheSize;
    protected int adjustMem;
    protected MemoryBudget budget;
    protected LookAheadCache lookAheadCache;
    protected Set checkPendingDbSet;
    protected Map dbCache;
    protected CleanerFileReader reader;
    protected DbTree dbMapTree;
    protected TreeLocation location;
    protected int nProcessedLNs;
    protected long lsn;
    protected long fileOffset;
    protected boolean isLN;
    protected boolean isIN;
    protected boolean isRoot;
    protected boolean isObsolete;
    protected DatabaseId dbId1;
    protected LN targetLN;
    protected DatabaseId dbId2;
    protected byte[] key;
    protected byte[] dupKey;
    protected Long aLsn;
    protected LNInfo aLninfo;
    protected Object p;
    protected IN targetIN;
    protected DatabaseId dbId3;
    protected DatabaseImpl db3;
    protected DatabaseId dbId;
    protected DatabaseImpl db;
    protected void hook119() throws DatabaseException, IOException {
    }
    protected void hook120() throws DatabaseException, IOException {
    }
    protected void hook127() throws DatabaseException, IOException {
    }
    protected void hook128() throws DatabaseException, IOException {
    }
    protected void hook129() throws DatabaseException, IOException {
    }
    protected void hook130() throws DatabaseException, IOException {
      p=null;
      this.hook131();
      _this.processLN(fileNum,location,aLsn,aLninfo,p,dbCache);
    }
    protected void hook131() throws DatabaseException, IOException {
    }
    protected void hook137() throws DatabaseException, IOException {
    }
    protected void hook145() throws DatabaseException, IOException {
    }
    protected void hook146() throws DatabaseException, IOException {
    }
    protected void hook147() throws DatabaseException, IOException {
    }
    protected void hook154() throws DatabaseException, IOException {
    }
    protected void hook155() throws DatabaseException, IOException {
    }
    protected void hook156() throws DatabaseException, IOException {
    }
    protected void hook161() throws DatabaseException, IOException {
    }
    protected void hook162() throws DatabaseException, IOException {
    }
  }
@MethodObject static class FileProcessor_processLN {
    FileProcessor_processLN(    FileProcessor _this,    Long fileNum,    TreeLocation location,    Long offset,    LNInfo info,    Object lookAheadCachep,    Map dbCache){
      this._this=_this;
      this.fileNum=fileNum;
      this.location=location;
      this.offset=offset;
      this.info=info;
      this.lookAheadCachep=lookAheadCachep;
      this.dbCache=dbCache;
    }
    void execute() throws DatabaseException {
      this.hook132();
      ln=info.getLN();
      key=info.getKey();
      dupKey=info.getDupKey();
      logLsn=DbLsn.makeLsn(fileNum.longValue(),offset.longValue());
      db=_this.env.getDbMapTree().getDb(info.getDbId(),_this.cleaner.lockTimeout,dbCache);
      processedHere=true;
      obsolete=false;
      completed=false;
      bin=null;
      parentDIN=null;
      try {
        b=db == null;
        this.hook157();
        if (b) {
          this.hook158();
          this.hook148();
          obsolete=true;
          completed=true;
          return;
        }
        tree=db.getTree();
        assert tree != null;
        parentFound=tree.getParentBINForChildLN(location,key,dupKey,ln,false,true,false,Cleaner.UPDATE_GENERATION);
        bin=location.bin;
        index=location.index;
        if (!parentFound) {
          this.hook149();
          obsolete=true;
          completed=true;
          return;
        }
        if (bin.isEntryKnownDeleted(index)) {
          this.hook150();
          obsolete=true;
          completed=true;
          return;
        }
        isDupCountLN=ln.containsDuplicates();
{
        }
        if (isDupCountLN) {
          parentDIN=(DIN)bin.fetchTarget(index);
          parentDIN.latch(Cleaner.UPDATE_GENERATION);
          dclRef=parentDIN.getDupCountLNRef();
          treeLsn=dclRef.getLsn();
        }
 else {
          treeLsn=bin.getLsn(index);
        }
        processedHere=false;
        _this.processFoundLN(info,logLsn,treeLsn,bin,index,parentDIN);
        completed=true;
        this.hook133();
        return;
      }
  finally {
        this.hook135();
        this.hook126();
      }
    }
    protected FileProcessor _this;
    protected Long fileNum;
    protected TreeLocation location;
    protected Long offset;
    protected LNInfo info;
    protected Object lookAheadCachep;
    protected Map dbCache;
    protected LookAheadCache lookAheadCache;
    protected LN ln;
    protected byte[] key;
    protected byte[] dupKey;
    protected long logLsn;
    protected DatabaseImpl db;
    protected boolean processedHere;
    protected boolean obsolete;
    protected boolean completed;
    protected BIN bin;
    protected DIN parentDIN;
    protected boolean b;
    protected Tree tree;
    protected boolean parentFound;
    protected int index;
    protected boolean isDupCountLN;
    protected long treeLsn;
    protected ChildReference dclRef;
    protected long lsn;
    protected Long myOffset;
    protected LNInfo myInfo;
    protected void hook126() throws DatabaseException {
    }
    protected void hook132() throws DatabaseException {
    }
    protected void hook133() throws DatabaseException {
    }
    protected void hook135() throws DatabaseException {
    }
    protected void hook148() throws DatabaseException {
    }
    protected void hook149() throws DatabaseException {
    }
    protected void hook150() throws DatabaseException {
    }
    protected void hook157() throws DatabaseException {
    }
    protected void hook158() throws DatabaseException {
    }
  }
  protected void hook121(  String traceMsg) throws DatabaseException, IOException {
  }
  protected void hook122(  IOException IOE) throws DatabaseException {
  }
  protected void hook123(  String traceMsg) throws DatabaseException {
  }
  protected void hook124(  long logLsn,  LN ln,  boolean obsolete,  boolean migrated,  boolean completed) throws DatabaseException {
  }
  protected void hook125(  IN inClone,  DatabaseImpl db,  long lsn,  boolean obsolete,  boolean dirtied,  boolean completed) throws DatabaseException {
    boolean b=db == null;
    b=this.hook159(db,b);
    if (b) {
      this.hook160(db);
      this.hook151();
      obsolete=true;
      completed=true;
      throw new ReturnVoid();
    }
    Tree tree=db.getTree();
    assert tree != null;
    IN inInTree=findINInTree(tree,db,inClone,lsn);
    if (inInTree == null) {
      this.hook152();
      obsolete=true;
    }
 else {
      this.hook153();
      inInTree.setDirty(true);
      inInTree.setProhibitNextDelta();
      this.hook136(inInTree);
      dirtied=true;
    }
    completed=true;
  }
  protected void hook134(  Tree tree,  DatabaseImpl db,  IN inClone,  long lsn,  SearchResult result) throws DatabaseException {
    result=tree.getParentINForChildIN(inClone,true,Cleaner.UPDATE_GENERATION,inClone.getLevel(),null);
    if (!result.exactParentFound) {
      throw new ReturnObject(null);
    }
    int compareVal=DbLsn.compareTo(result.parent.getLsn(result.index),lsn);
    if (compareVal > 0) {
      throw new ReturnObject(null);
    }
 else {
      IN in;
      if (compareVal == 0) {
        in=(IN)result.parent.getTarget(result.index);
        if (in == null) {
          in=inClone;
          in.postFetchInit(db,lsn);
          result.parent.updateEntry(result.index,in);
        }
      }
 else {
        in=(IN)result.parent.fetchTarget(result.index);
      }
      in.latch(Cleaner.UPDATE_GENERATION);
      throw new ReturnObject(in);
    }
  }
  protected void hook136(  IN inInTree) throws DatabaseException {
  }
  protected void hook138() throws DatabaseException {
  }
  protected String hook139(  String traceMsg) throws DatabaseException, IOException {
    return traceMsg;
  }
  protected void hook140() throws DatabaseException, IOException {
  }
  protected String hook141(  String traceMsg) throws DatabaseException {
    return traceMsg;
  }
  protected void hook142() throws DatabaseException {
  }
  protected void hook143() throws DatabaseException {
  }
  protected void hook144() throws DatabaseException {
  }
  protected void hook151() throws DatabaseException {
  }
  protected void hook152() throws DatabaseException {
  }
  protected void hook153() throws DatabaseException {
  }
  protected boolean hook159(  DatabaseImpl db,  boolean b) throws DatabaseException {
    return b;
  }
  protected void hook160(  DatabaseImpl db) throws DatabaseException {
  }
}
