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.

DeltaBaseCache.java 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /*
  2. * Copyright (C) 2011, Google Inc.
  3. * and other copyright owners as documented in the project's IP log.
  4. *
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Distribution License v1.0 which
  7. * accompanies this distribution, is reproduced below, and is
  8. * available at http://www.eclipse.org/org/documents/edl-v10.php
  9. *
  10. * All rights reserved.
  11. *
  12. * Redistribution and use in source and binary forms, with or
  13. * without modification, are permitted provided that the following
  14. * conditions are met:
  15. *
  16. * - Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. *
  19. * - Redistributions in binary form must reproduce the above
  20. * copyright notice, this list of conditions and the following
  21. * disclaimer in the documentation and/or other materials provided
  22. * with the distribution.
  23. *
  24. * - Neither the name of the Eclipse Foundation, Inc. nor the
  25. * names of its contributors may be used to endorse or promote
  26. * products derived from this software without specific prior
  27. * written permission.
  28. *
  29. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  30. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  31. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  32. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  34. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  38. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  41. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  42. */
  43. package org.eclipse.jgit.internal.storage.dfs;
  44. import java.lang.ref.SoftReference;
  45. /**
  46. * Caches recently used objects for {@link DfsReader}.
  47. * <p>
  48. * This cache is not thread-safe. Each reader should have its own cache.
  49. */
  50. final class DeltaBaseCache {
  51. private static final int TABLE_BITS = 10;
  52. private static final int MASK_BITS = 32 - TABLE_BITS;
  53. private static int hash(long position) {
  54. return (((int) position) << MASK_BITS) >>> MASK_BITS;
  55. }
  56. private int maxByteCount;
  57. private final Slot[] table;
  58. private Slot lruHead;
  59. private Slot lruTail;
  60. private int curByteCount;
  61. DeltaBaseCache(DfsReader reader) {
  62. this(reader.getOptions().getDeltaBaseCacheLimit());
  63. }
  64. DeltaBaseCache(int maxBytes) {
  65. maxByteCount = maxBytes;
  66. table = new Slot[1 << TABLE_BITS];
  67. }
  68. Entry get(DfsPackKey key, long position) {
  69. Slot e = table[hash(position)];
  70. for (; e != null; e = e.tableNext) {
  71. if (e.offset == position && key.equals(e.pack)) {
  72. Entry buf = e.data.get();
  73. if (buf != null) {
  74. moveToHead(e);
  75. return buf;
  76. }
  77. return null;
  78. }
  79. }
  80. return null;
  81. }
  82. void put(DfsPackKey key, long offset, int objectType, byte[] data) {
  83. if (data.length > maxByteCount)
  84. return; // Too large to cache.
  85. curByteCount += data.length;
  86. releaseMemory();
  87. int tableIdx = hash(offset);
  88. Slot e = new Slot(key, offset, data.length);
  89. e.data = new SoftReference<Entry>(new Entry(data, objectType));
  90. e.tableNext = table[tableIdx];
  91. table[tableIdx] = e;
  92. lruPushHead(e);
  93. }
  94. private void releaseMemory() {
  95. while (curByteCount > maxByteCount && lruTail != null) {
  96. Slot e = lruTail;
  97. curByteCount -= e.size;
  98. lruRemove(e);
  99. removeFromTable(e);
  100. }
  101. }
  102. private void removeFromTable(Slot e) {
  103. int tableIdx = hash(e.offset);
  104. Slot p = table[tableIdx];
  105. if (p == e) {
  106. table[tableIdx] = e.tableNext;
  107. return;
  108. }
  109. for (; p != null; p = p.tableNext) {
  110. if (p.tableNext == e) {
  111. p.tableNext = e.tableNext;
  112. return;
  113. }
  114. }
  115. throw new IllegalStateException(String.format(
  116. "entry for %s:%d not in table", //$NON-NLS-1$
  117. e.pack, Long.valueOf(e.offset)));
  118. }
  119. private void moveToHead(final Slot e) {
  120. if (e != lruHead) {
  121. lruRemove(e);
  122. lruPushHead(e);
  123. }
  124. }
  125. private void lruRemove(final Slot e) {
  126. Slot p = e.lruPrev;
  127. Slot n = e.lruNext;
  128. if (p != null) {
  129. p.lruNext = n;
  130. } else {
  131. lruHead = n;
  132. }
  133. if (n != null) {
  134. n.lruPrev = p;
  135. } else {
  136. lruTail = p;
  137. }
  138. }
  139. private void lruPushHead(final Slot e) {
  140. Slot n = lruHead;
  141. e.lruNext = n;
  142. if (n != null)
  143. n.lruPrev = e;
  144. else
  145. lruTail = e;
  146. e.lruPrev = null;
  147. lruHead = e;
  148. }
  149. int getMemoryUsed() {
  150. return curByteCount;
  151. }
  152. int getMemoryUsedByLruChainForTest() {
  153. int r = 0;
  154. for (Slot e = lruHead; e != null; e = e.lruNext) {
  155. r += e.size;
  156. }
  157. return r;
  158. }
  159. int getMemoryUsedByTableForTest() {
  160. int r = 0;
  161. for (int i = 0; i < table.length; i++) {
  162. for (Slot e = table[i]; e != null; e = e.tableNext) {
  163. r += e.size;
  164. }
  165. }
  166. return r;
  167. }
  168. static class Entry {
  169. final byte[] data;
  170. final int type;
  171. Entry(final byte[] aData, final int aType) {
  172. data = aData;
  173. type = aType;
  174. }
  175. }
  176. private static class Slot {
  177. final DfsPackKey pack;
  178. final long offset;
  179. final int size;
  180. Slot tableNext;
  181. Slot lruPrev;
  182. Slot lruNext;
  183. SoftReference<Entry> data;
  184. Slot(DfsPackKey key, long offset, int size) {
  185. this.pack = key;
  186. this.offset = offset;
  187. this.size = size;
  188. }
  189. }
  190. }