icache.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. #include "stdinc.h"
  2. #include "dat.h"
  3. #include "fns.h"
  4. typedef struct ICache ICache;
  5. struct ICache
  6. {
  7. VtLock *lock; /* locks hash table & all associated data */
  8. IEntry **heads; /* heads of all the hash chains */
  9. int bits; /* bits to use for indexing heads */
  10. u32int size; /* number of heads; == 1 << bits, should be < entries */
  11. IEntry *base; /* all allocated hash table entries */
  12. u32int entries; /* elements in base */
  13. u32int unused; /* index of first unused element in base */
  14. u32int stolen; /* last head from which an element was stolen */
  15. };
  16. static ICache icache;
  17. static IEntry *icacheAlloc(IAddr *ia, u8int *score);
  18. /*
  19. * bits is the number of bits in the icache hash table
  20. * depth is the average depth
  21. * memory usage is about (1<<bits) * depth * sizeof(IEntry) + (1<<bits) * sizeof(IEntry*)
  22. */
  23. void
  24. initICache(int bits, int depth)
  25. {
  26. icache.lock = vtLockAlloc();
  27. icache.bits = bits;
  28. icache.size = 1 << bits;
  29. icache.entries = depth * icache.size;
  30. icache.base = MKNZ(IEntry, icache.entries);
  31. icache.heads = MKNZ(IEntry*, icache.size);
  32. }
  33. u32int
  34. hashBits(u8int *sc, int bits)
  35. {
  36. u32int v;
  37. v = (sc[0] << 24) | (sc[1] << 16) | (sc[2] << 8) | sc[3];
  38. if(bits < 32)
  39. v >>= (32 - bits);
  40. return v;
  41. }
  42. /*
  43. ZZZ need to think about evicting the correct IEntry,
  44. and writing back the wtime.
  45. * look up data score in the index cache
  46. * if this fails, pull it in from the disk index table, if it exists.
  47. *
  48. * must be called with the lump for this score locked
  49. */
  50. int
  51. lookupScore(u8int *score, int type, IAddr *ia, int *rac)
  52. {
  53. IEntry d, *ie, *last;
  54. u32int h;
  55. vtLock(stats.lock);
  56. stats.icLookups++;
  57. vtUnlock(stats.lock);
  58. vtLock(icache.lock);
  59. h = hashBits(score, icache.bits);
  60. last = nil;
  61. for(ie = icache.heads[h]; ie != nil; ie = ie->next){
  62. if(ie->ia.type == type && scoreEq(ie->score, score)){
  63. if(last != nil)
  64. last->next = ie->next;
  65. else
  66. icache.heads[h] = ie->next;
  67. vtLock(stats.lock);
  68. stats.icHits++;
  69. vtUnlock(stats.lock);
  70. ie->rac = 1;
  71. goto found;
  72. }
  73. last = ie;
  74. }
  75. vtUnlock(icache.lock);
  76. if(!loadIEntry(mainIndex, score, type, &d))
  77. return 0;
  78. /*
  79. * no one else can load an entry for this score,
  80. * since we have the overall score lock.
  81. */
  82. vtLock(stats.lock);
  83. stats.icFills++;
  84. vtUnlock(stats.lock);
  85. vtLock(icache.lock);
  86. ie = icacheAlloc(&d.ia, score);
  87. found:
  88. ie->next = icache.heads[h];
  89. icache.heads[h] = ie;
  90. *ia = ie->ia;
  91. *rac = ie->rac;
  92. vtUnlock(icache.lock);
  93. return 1;
  94. }
  95. /*
  96. * insert a new element in the hash table.
  97. */
  98. int
  99. insertScore(u8int *score, IAddr *ia, int write)
  100. {
  101. IEntry *ie, se;
  102. u32int h;
  103. vtLock(stats.lock);
  104. stats.icInserts++;
  105. vtUnlock(stats.lock);
  106. vtLock(icache.lock);
  107. h = hashBits(score, icache.bits);
  108. ie = icacheAlloc(ia, score);
  109. ie->next = icache.heads[h];
  110. icache.heads[h] = ie;
  111. se = *ie;
  112. vtUnlock(icache.lock);
  113. if(!write)
  114. return 1;
  115. return storeIEntry(mainIndex, &se);
  116. }
  117. /*
  118. * allocate a index cache entry which hasn't been used in a while.
  119. * must be called with icache.lock locked
  120. * if the score is already in the table, update the entry.
  121. */
  122. static IEntry *
  123. icacheAlloc(IAddr *ia, u8int *score)
  124. {
  125. IEntry *ie, *last, *next;
  126. u32int h;
  127. h = hashBits(score, icache.bits);
  128. last = nil;
  129. for(ie = icache.heads[h]; ie != nil; ie = ie->next){
  130. if(ie->ia.type == ia->type && scoreEq(ie->score, score)){
  131. if(last != nil)
  132. last->next = ie->next;
  133. else
  134. icache.heads[h] = ie->next;
  135. ie->rac = 1;
  136. return ie;
  137. }
  138. last = ie;
  139. }
  140. h = icache.unused;
  141. if(h < icache.entries){
  142. ie = &icache.base[h++];
  143. icache.unused = h;
  144. goto Found;
  145. }
  146. h = icache.stolen;
  147. for(;;){
  148. h++;
  149. if(h >= icache.size)
  150. h = 0;
  151. ie = icache.heads[h];
  152. if(ie != nil){
  153. last = nil;
  154. for(; next = ie->next; ie = next)
  155. last = ie;
  156. if(last != nil)
  157. last->next = nil;
  158. else
  159. icache.heads[h] = nil;
  160. icache.stolen = h;
  161. goto Found;
  162. }
  163. }
  164. Found:
  165. ie->ia = *ia;
  166. scoreCp(ie->score, score);
  167. ie->rac = 0;
  168. return ie;
  169. }