/** Synchs in-core transactions to data file and opens a fresh log */
  private void synchronizeLogFromMemory() throws IOException {
    close();

    TreeSet<BlockIo> blockList = new TreeSet<BlockIo>(new BlockIoComparator());

    int numBlocks = 0;
    int writtenBlocks = 0;
    for (int i = 0; i < _maxTxns; i++) {
      if (txns[i] == null) continue;
      // Add each block to the blockList, replacing the old copy of this
      // block if necessary, thus avoiding writing the same block twice
      for (Iterator<BlockIo> k = txns[i].iterator(); k.hasNext(); ) {
        BlockIo block = k.next();
        if (blockList.contains(block)) {
          block.decrementTransactionCount();
        } else {
          writtenBlocks++;
          boolean result = blockList.add(block);
        }
        numBlocks++;
      }

      txns[i] = null;
    }
    // Write the blocks from the blockList to disk
    synchronizeBlocks(blockList, true);

    owner.sync();
    open();
  }
  /** Startup recovery on all files */
  private void recover() throws IOException {
    String logName = makeLogName();
    File logFile = new File(logName);
    if (!logFile.exists()) return;
    if (logFile.length() == 0) {
      logFile.delete();
      return;
    }

    FileInputStream fis = new FileInputStream(logFile);
    DataInputStream ois = new DataInputStream(new BufferedInputStream(fis));

    try {
      if (ois.readShort() != Magic.LOGFILE_HEADER) throw new Error("Bad magic on log file");
    } catch (IOException e) {
      // corrupted/empty logfile
      logFile.delete();
      return;
    }

    while (true) {
      ArrayList<BlockIo> blocks = null;
      try {
        blocks = (ArrayList<BlockIo>) Serialization.readObject(ois);
      } catch (ClassNotFoundException e) {
        throw new Error("Unexcepted exception: " + e);
      } catch (IOException e) {
        // corrupted logfile, ignore rest of transactions
        break;
      }
      synchronizeBlocks(blocks, false);

      // ObjectInputStream must match exactly each
      // ObjectOutputStream created during writes
      //            try {
      ois = new DataInputStream(fis);
      //            } catch (IOException e) {
      //                // corrupted logfile, ignore rest of transactions
      //                break;
      //            }
    }
    owner.sync();
    fis.close();
    logFile.delete();
  }