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

import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource;
import org.eclipse.jgit.internal.storage.pack.PackExt;
import org.eclipse.jgit.internal.storage.reftable.ReftableConfig;
import org.eclipse.jgit.lib.RefDatabase;

Git repository stored entirely in the local process memory.

This implementation builds on the DFS repository by storing all reference and object data in the local process. It is not very efficient and exists only for unit testing and small experiments.

The repository is thread-safe. Memory used is released only when this object is garbage collected. Closing the repository has no impact on its memory.

/** * Git repository stored entirely in the local process memory. * <p> * This implementation builds on the DFS repository by storing all reference and * object data in the local process. It is not very efficient and exists only * for unit testing and small experiments. * <p> * The repository is thread-safe. Memory used is released only when this object * is garbage collected. Closing the repository has no impact on its memory. */
public class InMemoryRepository extends DfsRepository {
Builder for in-memory repositories.
/** Builder for in-memory repositories. */
public static class Builder extends DfsRepositoryBuilder<Builder, InMemoryRepository> { @Override public InMemoryRepository build() throws IOException { return new InMemoryRepository(this); } } static final AtomicInteger packId = new AtomicInteger(); private final MemObjDatabase objdb; private final MemRefDatabase refdb; private String gitwebDescription;
Initialize a new in-memory repository.
Params:
  • repoDesc – description of the repository.
/** * Initialize a new in-memory repository. * * @param repoDesc * description of the repository. */
public InMemoryRepository(DfsRepositoryDescription repoDesc) { this(new Builder().setRepositoryDescription(repoDesc)); } InMemoryRepository(Builder builder) { super(builder); objdb = new MemObjDatabase(this); refdb = new MemRefDatabase(); }
{@inheritDoc}
/** {@inheritDoc} */
@Override public MemObjDatabase getObjectDatabase() { return objdb; }
{@inheritDoc}
/** {@inheritDoc} */
@Override public RefDatabase getRefDatabase() { return refdb; }
Enable (or disable) the atomic reference transaction support.

Useful for testing atomic support enabled or disabled.

Params:
  • atomic – whether to use atomic reference transaction support
/** * Enable (or disable) the atomic reference transaction support. * <p> * Useful for testing atomic support enabled or disabled. * * @param atomic * whether to use atomic reference transaction support */
public void setPerformsAtomicTransactions(boolean atomic) { refdb.performsAtomicTransactions = atomic; }
{@inheritDoc}
/** {@inheritDoc} */
@Override @Nullable public String getGitwebDescription() { return gitwebDescription; }
{@inheritDoc}
/** {@inheritDoc} */
@Override public void setGitwebDescription(@Nullable String d) { gitwebDescription = d; }
DfsObjDatabase used by InMemoryRepository.
/** DfsObjDatabase used by InMemoryRepository. */
public static class MemObjDatabase extends DfsObjDatabase { private List<DfsPackDescription> packs = new ArrayList<>(); private int blockSize; MemObjDatabase(DfsRepository repo) { super(repo, new DfsReaderOptions()); }
Params:
  • blockSize – force a different block size for testing.
/** * @param blockSize * force a different block size for testing. */
public void setReadableChannelBlockSizeForTest(int blockSize) { this.blockSize = blockSize; } @Override protected synchronized List<DfsPackDescription> listPacks() { return packs; } @Override protected DfsPackDescription newPack(PackSource source) { int id = packId.incrementAndGet(); return new MemPack( "pack-" + id + "-" + source.name(), //$NON-NLS-1$ //$NON-NLS-2$ getRepository().getDescription(), source); } @Override protected synchronized void commitPackImpl( Collection<DfsPackDescription> desc, Collection<DfsPackDescription> replace) { List<DfsPackDescription> n; n = new ArrayList<>(desc.size() + packs.size()); n.addAll(desc); n.addAll(packs); if (replace != null) n.removeAll(replace); packs = n; clearCache(); } @Override protected void rollbackPack(Collection<DfsPackDescription> desc) { // Do nothing. Pack is not recorded until commitPack. } @Override protected ReadableChannel openFile(DfsPackDescription desc, PackExt ext) throws FileNotFoundException, IOException { MemPack memPack = (MemPack) desc; byte[] file = memPack.get(ext); if (file == null) throw new FileNotFoundException(desc.getFileName(ext)); return new ByteArrayReadableChannel(file, blockSize); } @Override protected DfsOutputStream writeFile(DfsPackDescription desc, PackExt ext) throws IOException { MemPack memPack = (MemPack) desc; return new Out() { @Override public void flush() { memPack.put(ext, getData()); } }; } } private static class MemPack extends DfsPackDescription { final byte[][] fileMap = new byte[PackExt.values().length][]; MemPack(String name, DfsRepositoryDescription repoDesc, PackSource source) { super(repoDesc, name, source); } void put(PackExt ext, byte[] data) { fileMap[ext.getPosition()] = data; } byte[] get(PackExt ext) { return fileMap[ext.getPosition()]; } } private abstract static class Out extends DfsOutputStream { private final ByteArrayOutputStream dst = new ByteArrayOutputStream(); private byte[] data; @Override public void write(byte[] buf, int off, int len) { data = null; dst.write(buf, off, len); } @Override public int read(long position, ByteBuffer buf) { byte[] d = getData(); int n = Math.min(buf.remaining(), d.length - (int) position); if (n == 0) return -1; buf.put(d, (int) position, n); return n; } byte[] getData() { if (data == null) data = dst.toByteArray(); return data; } @Override public abstract void flush(); @Override public void close() { flush(); } } private static class ByteArrayReadableChannel implements ReadableChannel { private final byte[] data; private final int blockSize; private int position; private boolean open = true; ByteArrayReadableChannel(byte[] buf, int blockSize) { data = buf; this.blockSize = blockSize; } @Override public int read(ByteBuffer dst) { int n = Math.min(dst.remaining(), data.length - position); if (n == 0) return -1; dst.put(data, position, n); position += n; return n; } @Override public void close() { open = false; } @Override public boolean isOpen() { return open; } @Override public long position() { return position; } @Override public void position(long newPosition) { position = (int) newPosition; } @Override public long size() { return data.length; } @Override public int blockSize() { return blockSize; } @Override public void setReadAheadBytes(int b) { // Unnecessary on a byte array. } }
DfsRefDatabase used by InMemoryRepository.
/** DfsRefDatabase used by InMemoryRepository. */
protected class MemRefDatabase extends DfsReftableDatabase { boolean performsAtomicTransactions = true;
Initialize a new in-memory ref database.
/** Initialize a new in-memory ref database. */
protected MemRefDatabase() { super(InMemoryRepository.this); } @Override public ReftableConfig getReftableConfig() { ReftableConfig cfg = new ReftableConfig(); cfg.setAlignBlocks(false); cfg.setIndexObjects(false); cfg.fromConfig(getRepository().getConfig()); return cfg; } @Override public boolean performsAtomicTransactions() { return performsAtomicTransactions; } } }