icache.c 3.8 KB

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