123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- package org.eclipse.jgit.internal.storage.dfs;
-
- import java.io.FileNotFoundException;
- import java.io.IOException;
- import java.nio.ByteBuffer;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.concurrent.ConcurrentHashMap;
- import java.util.concurrent.ConcurrentMap;
- import java.util.concurrent.atomic.AtomicInteger;
-
- import org.eclipse.jgit.internal.storage.pack.PackExt;
- import org.eclipse.jgit.lib.Ref;
- import org.eclipse.jgit.lib.Ref.Storage;
- import org.eclipse.jgit.util.RefList;
-
- /**
- * 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 {
- private static final AtomicInteger packId = new AtomicInteger();
-
- private final DfsObjDatabase objdb;
-
- private final DfsRefDatabase refdb;
-
- /**
- * Initialize a new in-memory repository.
- *
- * @param repoDesc
- * description of the repository.
- * @since 2.0
- */
- public InMemoryRepository(DfsRepositoryDescription repoDesc) {
- super(new DfsRepositoryBuilder<DfsRepositoryBuilder, InMemoryRepository>() {
- @Override
- public InMemoryRepository build() throws IOException {
- throw new UnsupportedOperationException();
- }
- }.setRepositoryDescription(repoDesc));
-
- objdb = new MemObjDatabase(this);
- refdb = new MemRefDatabase();
- }
-
- @Override
- public DfsObjDatabase getObjectDatabase() {
- return objdb;
- }
-
- @Override
- public DfsRefDatabase getRefDatabase() {
- return refdb;
- }
-
- private class MemObjDatabase extends DfsObjDatabase {
- private List<DfsPackDescription> packs = new ArrayList<DfsPackDescription>();
-
- MemObjDatabase(DfsRepository repo) {
- super(repo, new DfsReaderOptions());
- }
-
- @Override
- protected synchronized List<DfsPackDescription> listPacks() {
- return packs;
- }
-
- @Override
- protected DfsPackDescription newPack(PackSource source) {
- int id = packId.incrementAndGet();
- DfsPackDescription desc = new MemPack(
- "pack-" + id + "-" + source.name(), //$NON-NLS-1$ //$NON-NLS-2$
- getRepository().getDescription());
- return desc.setPackSource(source);
- }
-
- @Override
- protected synchronized void commitPackImpl(
- Collection<DfsPackDescription> desc,
- Collection<DfsPackDescription> replace) {
- List<DfsPackDescription> n;
- n = new ArrayList<DfsPackDescription>(desc.size() + packs.size());
- n.addAll(desc);
- n.addAll(packs);
- if (replace != null)
- n.removeAll(replace);
- packs = n;
- }
-
- @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.fileMap.get(ext);
- if (file == null)
- throw new FileNotFoundException(desc.getFileName(ext));
- return new ByteArrayReadableChannel(file);
- }
-
- @Override
- protected DfsOutputStream writeFile(
- DfsPackDescription desc, final PackExt ext) throws IOException {
- final MemPack memPack = (MemPack) desc;
- return new InMemoryOutputStream() {
- @Override
- public void flush() {
- memPack.fileMap.put(ext, getData());
- }
- };
- }
- }
-
- private static class MemPack extends DfsPackDescription {
- private final Map<PackExt, byte[]>
- fileMap = new HashMap<PackExt, byte[]>();
-
- MemPack(String name, DfsRepositoryDescription repoDesc) {
- super(repoDesc, name);
- }
- }
-
- private static class ByteArrayReadableChannel implements ReadableChannel {
- private final byte[] data;
-
- private int position;
-
- private boolean open = true;
-
- ByteArrayReadableChannel(byte[] buf) {
- data = buf;
- }
-
- 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;
- }
-
- public void close() {
- open = false;
- }
-
- public boolean isOpen() {
- return open;
- }
-
- public long position() {
- return position;
- }
-
- public void position(long newPosition) {
- position = (int) newPosition;
- }
-
- public long size() {
- return data.length;
- }
-
- public int blockSize() {
- return 0;
- }
- }
-
- private class MemRefDatabase extends DfsRefDatabase {
- private final ConcurrentMap<String, Ref> refs = new ConcurrentHashMap<String, Ref>();
-
- MemRefDatabase() {
- super(InMemoryRepository.this);
- }
-
- @Override
- protected RefCache scanAllRefs() throws IOException {
- RefList.Builder<Ref> ids = new RefList.Builder<Ref>();
- RefList.Builder<Ref> sym = new RefList.Builder<Ref>();
- for (Ref ref : refs.values()) {
- if (ref.isSymbolic())
- sym.add(ref);
- ids.add(ref);
- }
- ids.sort();
- sym.sort();
- return new RefCache(ids.toRefList(), sym.toRefList());
- }
-
- @Override
- protected boolean compareAndPut(Ref oldRef, Ref newRef)
- throws IOException {
- String name = newRef.getName();
- if (oldRef == null || oldRef.getStorage() == Storage.NEW)
- return refs.putIfAbsent(name, newRef) == null;
- Ref cur = refs.get(name);
- if (cur != null && eq(cur, oldRef))
- return refs.replace(name, cur, newRef);
- else
- return false;
-
- }
-
- @Override
- protected boolean compareAndRemove(Ref oldRef) throws IOException {
- String name = oldRef.getName();
- Ref cur = refs.get(name);
- if (cur != null && eq(cur, oldRef))
- return refs.remove(name, cur);
- else
- return false;
- }
-
- private boolean eq(Ref a, Ref b) {
- if (a.getObjectId() == null && b.getObjectId() == null)
- return true;
- if (a.getObjectId() != null)
- return a.getObjectId().equals(b.getObjectId());
- return false;
- }
- }
- }
|