Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

InMemoryRepository.java 7.0KB

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