DfsReftable.java

  1. /*
  2.  * Copyright (C) 2017, Google Inc. and others
  3.  *
  4.  * This program and the accompanying materials are made available under the
  5.  * terms of the Eclipse Distribution License v. 1.0 which is available at
  6.  * https://www.eclipse.org/org/documents/edl-v10.php.
  7.  *
  8.  * SPDX-License-Identifier: BSD-3-Clause
  9.  */

  10. package org.eclipse.jgit.internal.storage.dfs;

  11. import static org.eclipse.jgit.internal.storage.pack.PackExt.REFTABLE;

  12. import java.io.IOException;
  13. import java.nio.ByteBuffer;

  14. import org.eclipse.jgit.internal.storage.io.BlockSource;
  15. import org.eclipse.jgit.internal.storage.reftable.ReftableReader;

  16. /**
  17.  * A reftable stored in {@link org.eclipse.jgit.internal.storage.dfs.DfsBlockCache}.
  18.  */
  19. public class DfsReftable extends BlockBasedFile {
  20.     /**
  21.      * Construct a reader for an existing reftable.
  22.      *
  23.      * @param desc
  24.      *            description of the reftable within the DFS.
  25.      */
  26.     public DfsReftable(DfsPackDescription desc) {
  27.         this(DfsBlockCache.getInstance(), desc);
  28.     }

  29.     /**
  30.      * Construct a reader for an existing reftable.
  31.      *
  32.      * @param cache
  33.      *            cache that will store the reftable data.
  34.      * @param desc
  35.      *            description of the reftable within the DFS.
  36.      */
  37.     public DfsReftable(DfsBlockCache cache, DfsPackDescription desc) {
  38.         super(cache, desc, REFTABLE);

  39.         int bs = desc.getBlockSize(REFTABLE);
  40.         if (bs > 0) {
  41.             setBlockSize(bs);
  42.         }

  43.         long sz = desc.getFileSize(REFTABLE);
  44.         length = sz > 0 ? sz : -1;
  45.     }

  46.     /**
  47.      * Get description that was originally used to configure this file.
  48.      *
  49.      * @return description that was originally used to configure this file.
  50.      */
  51.     public DfsPackDescription getPackDescription() {
  52.         return desc;
  53.     }

  54.     /**
  55.      * Open reader on the reftable.
  56.      * <p>
  57.      * The returned reader is not thread safe.
  58.      *
  59.      * @param ctx
  60.      *            reader to access the DFS storage.
  61.      * @return cursor to read the table; caller must close.
  62.      * @throws java.io.IOException
  63.      *             table cannot be opened.
  64.      */
  65.     public ReftableReader open(DfsReader ctx) throws IOException {
  66.         return new ReftableReader(new CacheSource(this, cache, ctx));
  67.     }

  68.     private static final class CacheSource extends BlockSource {
  69.         private final DfsReftable file;
  70.         private final DfsBlockCache cache;
  71.         private final DfsReader ctx;
  72.         private ReadableChannel ch;
  73.         private int readAhead;

  74.         CacheSource(DfsReftable file, DfsBlockCache cache, DfsReader ctx) {
  75.             this.file = file;
  76.             this.cache = cache;
  77.             this.ctx = ctx;
  78.         }

  79.         @Override
  80.         public ByteBuffer read(long pos, int cnt) throws IOException {
  81.             if (ch == null && readAhead > 0 && notInCache(pos)) {
  82.                 open().setReadAheadBytes(readAhead);
  83.             }

  84.             DfsBlock block = cache.getOrLoad(file, pos, ctx, () -> open());
  85.             if (block.start == pos && block.size() >= cnt) {
  86.                 return block.zeroCopyByteBuffer(cnt);
  87.             }

  88.             byte[] dst = new byte[cnt];
  89.             ByteBuffer buf = ByteBuffer.wrap(dst);
  90.             buf.position(ctx.copy(file, pos, dst, 0, cnt));
  91.             return buf;
  92.         }

  93.         private boolean notInCache(long pos) {
  94.             return cache.get(file.key, file.alignToBlock(pos)) == null;
  95.         }

  96.         @Override
  97.         public long size() throws IOException {
  98.             long n = file.length;
  99.             if (n < 0) {
  100.                 n = open().size();
  101.                 file.length = n;
  102.             }
  103.             return n;
  104.         }

  105.         @Override
  106.         public void adviseSequentialRead(long start, long end) {
  107.             int sz = ctx.getOptions().getStreamPackBufferSize();
  108.             if (sz > 0) {
  109.                 readAhead = (int) Math.min(sz, end - start);
  110.             }
  111.         }

  112.         private ReadableChannel open() throws IOException {
  113.             if (ch == null) {
  114.                 ch = ctx.db.openFile(file.desc, file.ext);
  115.             }
  116.             return ch;
  117.         }

  118.         @Override
  119.         public void close() {
  120.             if (ch != null) {
  121.                 try {
  122.                     ch.close();
  123.                 } catch (IOException e) {
  124.                     // Ignore read close failures.
  125.                 } finally {
  126.                     ch = null;
  127.                 }
  128.             }
  129.         }
  130.     }
  131. }