You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

InMemoryRepository.java 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. package org.eclipse.jgit.internal.storage.dfs;
  2. import java.io.FileNotFoundException;
  3. import java.io.IOException;
  4. import java.nio.ByteBuffer;
  5. import java.util.ArrayList;
  6. import java.util.Collection;
  7. import java.util.HashMap;
  8. import java.util.List;
  9. import java.util.Map;
  10. import java.util.concurrent.ConcurrentHashMap;
  11. import java.util.concurrent.ConcurrentMap;
  12. import java.util.concurrent.atomic.AtomicInteger;
  13. import org.eclipse.jgit.internal.storage.pack.PackExt;
  14. import org.eclipse.jgit.lib.Ref;
  15. import org.eclipse.jgit.lib.Ref.Storage;
  16. import org.eclipse.jgit.util.RefList;
  17. /**
  18. * Git repository stored entirely in the local process memory.
  19. * <p>
  20. * This implementation builds on the DFS repository by storing all reference and
  21. * object data in the local process. It is not very efficient and exists only
  22. * for unit testing and small experiments.
  23. * <p>
  24. * The repository is thread-safe. Memory used is released only when this object
  25. * is garbage collected. Closing the repository has no impact on its memory.
  26. */
  27. public class InMemoryRepository extends DfsRepository {
  28. private static final AtomicInteger packId = new AtomicInteger();
  29. private final DfsObjDatabase objdb;
  30. private final DfsRefDatabase refdb;
  31. /**
  32. * Initialize a new in-memory repository.
  33. *
  34. * @param repoDesc
  35. * description of the repository.
  36. * @since 2.0
  37. */
  38. public InMemoryRepository(DfsRepositoryDescription repoDesc) {
  39. super(new DfsRepositoryBuilder<DfsRepositoryBuilder, InMemoryRepository>() {
  40. @Override
  41. public InMemoryRepository build() throws IOException {
  42. throw new UnsupportedOperationException();
  43. }
  44. }.setRepositoryDescription(repoDesc));
  45. objdb = new MemObjDatabase(this);
  46. refdb = new MemRefDatabase();
  47. }
  48. @Override
  49. public DfsObjDatabase getObjectDatabase() {
  50. return objdb;
  51. }
  52. @Override
  53. public DfsRefDatabase getRefDatabase() {
  54. return refdb;
  55. }
  56. private class MemObjDatabase extends DfsObjDatabase {
  57. private List<DfsPackDescription> packs = new ArrayList<DfsPackDescription>();
  58. MemObjDatabase(DfsRepository repo) {
  59. super(repo, new DfsReaderOptions());
  60. }
  61. @Override
  62. protected synchronized List<DfsPackDescription> listPacks() {
  63. return packs;
  64. }
  65. @Override
  66. protected DfsPackDescription newPack(PackSource source) {
  67. int id = packId.incrementAndGet();
  68. DfsPackDescription desc = new MemPack(
  69. "pack-" + id + "-" + source.name(), //$NON-NLS-1$ //$NON-NLS-2$
  70. getRepository().getDescription());
  71. return desc.setPackSource(source);
  72. }
  73. @Override
  74. protected synchronized void commitPackImpl(
  75. Collection<DfsPackDescription> desc,
  76. Collection<DfsPackDescription> replace) {
  77. List<DfsPackDescription> n;
  78. n = new ArrayList<DfsPackDescription>(desc.size() + packs.size());
  79. n.addAll(desc);
  80. n.addAll(packs);
  81. if (replace != null)
  82. n.removeAll(replace);
  83. packs = n;
  84. }
  85. @Override
  86. protected void rollbackPack(Collection<DfsPackDescription> desc) {
  87. // Do nothing. Pack is not recorded until commitPack.
  88. }
  89. @Override
  90. protected ReadableChannel openFile(DfsPackDescription desc, PackExt ext)
  91. throws FileNotFoundException, IOException {
  92. MemPack memPack = (MemPack) desc;
  93. byte[] file = memPack.fileMap.get(ext);
  94. if (file == null)
  95. throw new FileNotFoundException(desc.getFileName(ext));
  96. return new ByteArrayReadableChannel(file);
  97. }
  98. @Override
  99. protected DfsOutputStream writeFile(
  100. DfsPackDescription desc, final PackExt ext) throws IOException {
  101. final MemPack memPack = (MemPack) desc;
  102. return new InMemoryOutputStream() {
  103. @Override
  104. public void flush() {
  105. memPack.fileMap.put(ext, getData());
  106. }
  107. };
  108. }
  109. }
  110. private static class MemPack extends DfsPackDescription {
  111. private final Map<PackExt, byte[]>
  112. fileMap = new HashMap<PackExt, byte[]>();
  113. MemPack(String name, DfsRepositoryDescription repoDesc) {
  114. super(repoDesc, name);
  115. }
  116. }
  117. private static class ByteArrayReadableChannel implements ReadableChannel {
  118. private final byte[] data;
  119. private int position;
  120. private boolean open = true;
  121. ByteArrayReadableChannel(byte[] buf) {
  122. data = buf;
  123. }
  124. public int read(ByteBuffer dst) {
  125. int n = Math.min(dst.remaining(), data.length - position);
  126. if (n == 0)
  127. return -1;
  128. dst.put(data, position, n);
  129. position += n;
  130. return n;
  131. }
  132. public void close() {
  133. open = false;
  134. }
  135. public boolean isOpen() {
  136. return open;
  137. }
  138. public long position() {
  139. return position;
  140. }
  141. public void position(long newPosition) {
  142. position = (int) newPosition;
  143. }
  144. public long size() {
  145. return data.length;
  146. }
  147. public int blockSize() {
  148. return 0;
  149. }
  150. }
  151. private class MemRefDatabase extends DfsRefDatabase {
  152. private final ConcurrentMap<String, Ref> refs = new ConcurrentHashMap<String, Ref>();
  153. MemRefDatabase() {
  154. super(InMemoryRepository.this);
  155. }
  156. @Override
  157. protected RefCache scanAllRefs() throws IOException {
  158. RefList.Builder<Ref> ids = new RefList.Builder<Ref>();
  159. RefList.Builder<Ref> sym = new RefList.Builder<Ref>();
  160. for (Ref ref : refs.values()) {
  161. if (ref.isSymbolic())
  162. sym.add(ref);
  163. ids.add(ref);
  164. }
  165. ids.sort();
  166. sym.sort();
  167. return new RefCache(ids.toRefList(), sym.toRefList());
  168. }
  169. @Override
  170. protected boolean compareAndPut(Ref oldRef, Ref newRef)
  171. throws IOException {
  172. String name = newRef.getName();
  173. if (oldRef == null || oldRef.getStorage() == Storage.NEW)
  174. return refs.putIfAbsent(name, newRef) == null;
  175. Ref cur = refs.get(name);
  176. if (cur != null && eq(cur, oldRef))
  177. return refs.replace(name, cur, newRef);
  178. else
  179. return false;
  180. }
  181. @Override
  182. protected boolean compareAndRemove(Ref oldRef) throws IOException {
  183. String name = oldRef.getName();
  184. Ref cur = refs.get(name);
  185. if (cur != null && eq(cur, oldRef))
  186. return refs.remove(name, cur);
  187. else
  188. return false;
  189. }
  190. private boolean eq(Ref a, Ref b) {
  191. if (a.getObjectId() == null && b.getObjectId() == null)
  192. return true;
  193. if (a.getObjectId() != null)
  194. return a.getObjectId().equals(b.getObjectId());
  195. return false;
  196. }
  197. }
  198. }