public synchronized StoredBlock get(Sha256Hash hash) throws BlockStoreException {
    ensureOpen();
    // Check the memory cache first.
    StoredBlock fromMem = blockCache.get(hash);
    if (fromMem != null) {
      return fromMem;
    }
    if (notFoundCache.get(hash) == notFoundMarker) {
      return null;
    }

    try {
      Record fromDisk = getRecord(hash);
      StoredBlock block = null;
      if (fromDisk == null) {
        notFoundCache.put(hash, notFoundMarker);
      } else {
        block = fromDisk.toStoredBlock(params);
        blockCache.put(hash, block);
      }
      return block;
    } catch (IOException e) {
      throw new BlockStoreException(e);
    } catch (ProtocolException e) {
      throw new BlockStoreException(e);
    }
  }
 private Record getRecord(Sha256Hash hash) throws IOException, ProtocolException {
   long startPos = channel.position();
   // Use our own file pointer within the tight loop as updating channel positions is really
   // expensive.
   long pos = startPos;
   Record record = new Record();
   int numMoves = 0;
   long startTime = new Date().getTime();
   do {
     if (!record.read(channel, pos, buf)) throw new IOException("Failed to read buffer");
     if (record.getHeader(params).getHash().equals(hash)) {
       // Found it. Update file position for next time.
       channel.position(pos);
       long endTime = new Date().getTime();
       if (endTime - startTime > 100) {
         log.info(
             "Spent {} seconds doing {} backwards seeks",
             (endTime - startTime) / 1000.0,
             numMoves);
       }
       return record;
     }
     // Did not find it.
     if (pos == 1 + 32) {
       // At the start so wrap around to the end.
       pos = channel.size() - Record.SIZE;
     } else {
       // Move backwards.
       pos = pos - Record.SIZE;
       checkState(pos >= 1 + 32, pos);
     }
     numMoves++;
   } while (pos != startPos);
   // Was never stored.
   channel.position(pos);
   long endTime = new Date().getTime();
   if (endTime - startTime > 1000) {
     log.info(
         "Spent {} seconds doing {} backwards seeks", (endTime - startTime) / 1000.0, numMoves);
   }
   return null;
 }
 public synchronized void put(StoredBlock block) throws BlockStoreException {
   ensureOpen();
   try {
     Sha256Hash hash = block.getHeader().getHash();
     // Append to the end of the file.
     Record.write(channel, block);
     blockCache.put(hash, block);
   } catch (IOException e) {
     throw new BlockStoreException(e);
   }
 }