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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /*
  2. * Copyright (C) 2011, Google Inc. and others
  3. *
  4. * This program and the accompanying materials are made available under the
  5. * terms of the Eclipse Distribution License v. 1.0 which is available at
  6. * https://www.eclipse.org/org/documents/edl-v10.php.
  7. *
  8. * SPDX-License-Identifier: BSD-3-Clause
  9. */
  10. package org.eclipse.jgit.internal.storage.dfs;
  11. /**
  12. * Caches recently used objects for {@link DfsReader}.
  13. * <p>
  14. * This cache is not thread-safe. Each reader should have its own cache.
  15. */
  16. final class DeltaBaseCache {
  17. private static final int TABLE_BITS = 10;
  18. private static final int MASK_BITS = 32 - TABLE_BITS;
  19. private static int hash(long position) {
  20. return (((int) position) << MASK_BITS) >>> MASK_BITS;
  21. }
  22. private int maxByteCount;
  23. private int curByteCount;
  24. private final Entry[] table;
  25. private Entry lruHead;
  26. private Entry lruTail;
  27. DeltaBaseCache(DfsReader reader) {
  28. this(reader.getOptions().getDeltaBaseCacheLimit());
  29. }
  30. DeltaBaseCache(int maxBytes) {
  31. maxByteCount = maxBytes;
  32. table = new Entry[1 << TABLE_BITS];
  33. }
  34. Entry get(DfsStreamKey key, long position) {
  35. Entry e = table[hash(position)];
  36. for (; e != null; e = e.tableNext) {
  37. if (e.offset == position && key.equals(e.pack)) {
  38. moveToHead(e);
  39. return e;
  40. }
  41. }
  42. return null;
  43. }
  44. void put(DfsStreamKey key, long offset, int objectType, byte[] data) {
  45. if (data.length > maxByteCount)
  46. return; // Too large to cache.
  47. curByteCount += data.length;
  48. releaseMemory();
  49. int tableIdx = hash(offset);
  50. Entry e = new Entry(key, offset, objectType, data);
  51. e.tableNext = table[tableIdx];
  52. table[tableIdx] = e;
  53. lruPushHead(e);
  54. }
  55. private void releaseMemory() {
  56. while (curByteCount > maxByteCount && lruTail != null) {
  57. Entry e = lruTail;
  58. curByteCount -= e.data.length;
  59. lruRemove(e);
  60. removeFromTable(e);
  61. }
  62. }
  63. private void removeFromTable(Entry e) {
  64. int tableIdx = hash(e.offset);
  65. Entry p = table[tableIdx];
  66. if (p == e) {
  67. table[tableIdx] = e.tableNext;
  68. return;
  69. }
  70. for (; p != null; p = p.tableNext) {
  71. if (p.tableNext == e) {
  72. p.tableNext = e.tableNext;
  73. return;
  74. }
  75. }
  76. throw new IllegalStateException(String.format(
  77. "entry for %s:%d not in table", //$NON-NLS-1$
  78. e.pack, Long.valueOf(e.offset)));
  79. }
  80. private void moveToHead(Entry e) {
  81. if (e != lruHead) {
  82. lruRemove(e);
  83. lruPushHead(e);
  84. }
  85. }
  86. private void lruRemove(Entry e) {
  87. Entry p = e.lruPrev;
  88. Entry n = e.lruNext;
  89. if (p != null) {
  90. p.lruNext = n;
  91. } else {
  92. lruHead = n;
  93. }
  94. if (n != null) {
  95. n.lruPrev = p;
  96. } else {
  97. lruTail = p;
  98. }
  99. }
  100. private void lruPushHead(Entry e) {
  101. Entry n = lruHead;
  102. e.lruNext = n;
  103. if (n != null)
  104. n.lruPrev = e;
  105. else
  106. lruTail = e;
  107. e.lruPrev = null;
  108. lruHead = e;
  109. }
  110. int getMemoryUsed() {
  111. return curByteCount;
  112. }
  113. int getMemoryUsedByLruChainForTest() {
  114. int r = 0;
  115. for (Entry e = lruHead; e != null; e = e.lruNext) {
  116. r += e.data.length;
  117. }
  118. return r;
  119. }
  120. int getMemoryUsedByTableForTest() {
  121. int r = 0;
  122. for (Entry t : table) {
  123. for (Entry e = t; e != null; e = e.tableNext) {
  124. r += e.data.length;
  125. }
  126. }
  127. return r;
  128. }
  129. static class Entry {
  130. final DfsStreamKey pack;
  131. final long offset;
  132. final int type;
  133. final byte[] data;
  134. Entry tableNext;
  135. Entry lruPrev;
  136. Entry lruNext;
  137. Entry(DfsStreamKey key, long offset, int type, byte[] data) {
  138. this.pack = key;
  139. this.offset = offset;
  140. this.type = type;
  141. this.data = data;
  142. }
  143. }
  144. }