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.9KB

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