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 6.7KB

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