source.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. #include "stdinc.h"
  2. #include "vac.h"
  3. #include "dat.h"
  4. #include "fns.h"
  5. #include "error.h"
  6. static int sizeToDepth(uvlong s, int psize, int dsize);
  7. static int
  8. sizeToDepth(uvlong s, int psize, int dsize)
  9. {
  10. int np;
  11. int d;
  12. /* determine pointer depth */
  13. np = psize/VtScoreSize;
  14. s = (s + dsize - 1)/dsize;
  15. for(d = 0; s > 1; d++)
  16. s = (s + np - 1)/np;
  17. return d;
  18. }
  19. /* assumes u is lock? */
  20. Source *
  21. sourceAlloc(Cache *c, Lump *u, ulong block, int entry, int readOnly)
  22. {
  23. Source *r;
  24. VtEntry d;
  25. if(u->asize < (entry+1)*VtEntrySize) {
  26. vtSetError(ENoDir);
  27. return nil;
  28. }
  29. if(!vtEntryUnpack(&d, u->data, entry))
  30. return nil;
  31. if(!(d.flags & VtEntryActive)) {
  32. fprint(2, "%s: bad flags %#ux %V\n", argv0, d.flags, d.score);
  33. vtSetError(ENoDir);
  34. return nil;
  35. }
  36. /* HACK for backwards compatiblity - should go away at some point */
  37. if(d.depth == 0) {
  38. if(d.size > d.dsize) fprint(2, "%s: depth == 0! size = %ulld\n", argv0, d.size);
  39. d.depth = sizeToDepth(d.size, d.psize, d.dsize);
  40. }
  41. if(d.depth < sizeToDepth(d.size, d.psize, d.dsize)) {
  42. vtSetError(EBadDir);
  43. return nil;
  44. }
  45. r = vtMemAllocZ(sizeof(Source));
  46. r->lk = vtLockAlloc();
  47. r->cache = c;
  48. r->readOnly = readOnly;
  49. r->lump = lumpIncRef(u);
  50. r->block = block;
  51. r->entry = entry;
  52. r->gen = d.gen;
  53. r->dir = (d.flags & VtEntryDir) != 0;
  54. r->depth = d.depth;
  55. r->psize = d.psize;
  56. r->dsize = d.dsize;
  57. r->size = d.size;
  58. r->epb = r->dsize/VtEntrySize;
  59. return r;
  60. }
  61. Source *
  62. sourceOpen(Source *r, ulong entry, int readOnly)
  63. {
  64. ulong bn;
  65. Lump *u;
  66. if(0)fprint(2, "%s: sourceOpen: %V:%d: %lud\n", argv0, r->lump->score, r->entry, entry);
  67. if(r->readOnly && !readOnly) {
  68. vtSetError(EReadOnly);
  69. return nil;
  70. }
  71. bn = entry/r->epb;
  72. u = sourceGetLump(r, bn, readOnly, 1);
  73. if(u == nil)
  74. return nil;
  75. r = sourceAlloc(r->cache, u, bn, entry%r->epb, readOnly);
  76. lumpDecRef(u, 1);
  77. return r;
  78. }
  79. Source *
  80. sourceCreate(Source *r, int psize, int dsize, int isdir, ulong entry)
  81. {
  82. Source *rr;
  83. int i;
  84. Lump *u;
  85. ulong bn;
  86. VtEntry dir;
  87. if(r->readOnly) {
  88. vtSetError(EReadOnly);
  89. return nil;
  90. }
  91. if(entry == 0) {
  92. /*
  93. * look at a random block to see if we can find an empty entry
  94. */
  95. entry = sourceGetDirSize(r);
  96. entry = r->epb*lnrand(entry/r->epb+1);
  97. }
  98. /*
  99. * need to loop since multiple threads could be trying to allocate
  100. */
  101. for(;;) {
  102. bn = entry/r->epb;
  103. sourceSetDepth(r, (uvlong)(bn+1)*r->dsize);
  104. u = sourceGetLump(r, bn, 0, 1);
  105. if(u == nil)
  106. return nil;
  107. for(i=entry%r->epb; i<r->epb; i++) {
  108. vtEntryUnpack(&dir, u->data, i);
  109. if((dir.flags&VtEntryActive) == 0 && dir.gen != ~0)
  110. goto Found;
  111. }
  112. lumpDecRef(u, 1);
  113. entry = sourceGetDirSize(r);
  114. }
  115. Found:
  116. /* found an entry */
  117. dir.psize = psize;
  118. dir.dsize = dsize;
  119. dir.flags = VtEntryActive;
  120. if(isdir)
  121. dir.flags |= VtEntryDir;
  122. dir.depth = 0;
  123. dir.size = 0;
  124. memmove(dir.score, vtZeroScore, VtScoreSize);
  125. vtEntryPack(&dir, u->data, i);
  126. sourceSetDirSize(r, bn*r->epb + i + 1);
  127. rr = sourceAlloc(r->cache, u, bn, i, 0);
  128. lumpDecRef(u, 1);
  129. return rr;
  130. }
  131. void
  132. sourceRemove(Source *r)
  133. {
  134. lumpFreeEntry(r->lump, r->entry);
  135. sourceFree(r);
  136. }
  137. int
  138. sourceSetDepth(Source *r, uvlong size)
  139. {
  140. Lump *u, *v;
  141. VtEntry dir;
  142. int depth;
  143. if(r->readOnly){
  144. vtSetError(EReadOnly);
  145. return 0;
  146. }
  147. depth = sizeToDepth(size, r->psize, r->dsize);
  148. assert(depth >= 0);
  149. if(depth > VtPointerDepth) {
  150. vtSetError(ETooBig);
  151. return 0;
  152. }
  153. vtLock(r->lk);
  154. if(r->depth >= depth) {
  155. vtUnlock(r->lk);
  156. return 1;
  157. }
  158. u = r->lump;
  159. vtLock(u->lk);
  160. if(!vtEntryUnpack(&dir, u->data, r->entry)) {
  161. vtUnlock(u->lk);
  162. vtUnlock(r->lk);
  163. return 0;
  164. }
  165. while(dir.depth < depth) {
  166. v = cacheAllocLump(r->cache, VtPointerType0+r->depth, r->psize, r->dir);
  167. if(v == nil)
  168. break;
  169. memmove(v->data, dir.score, VtScoreSize);
  170. memmove(dir.score, v->score, VtScoreSize);
  171. dir.depth++;
  172. vtUnlock(v->lk);
  173. }
  174. vtEntryPack(&dir, u->data, r->entry);
  175. vtUnlock(u->lk);
  176. r->depth = dir.depth;
  177. vtUnlock(r->lk);
  178. return dir.depth == depth;
  179. }
  180. int
  181. sourceGetVtEntry(Source *r, VtEntry *dir)
  182. {
  183. Lump *u;
  184. u = r->lump;
  185. vtLock(u->lk);
  186. if(!vtEntryUnpack(dir, u->data, r->entry)) {
  187. vtUnlock(u->lk);
  188. return 0;
  189. }
  190. vtUnlock(u->lk);
  191. return 1;
  192. }
  193. uvlong
  194. sourceGetSize(Source *r)
  195. {
  196. uvlong size;
  197. vtLock(r->lk);
  198. size = r->size;
  199. vtUnlock(r->lk);
  200. return size;
  201. }
  202. int
  203. sourceSetSize(Source *r, uvlong size)
  204. {
  205. Lump *u;
  206. VtEntry dir;
  207. int depth;
  208. if(r->readOnly) {
  209. vtSetError(EReadOnly);
  210. return 0;
  211. }
  212. if(size > VtMaxFileSize || size > ((uvlong)MaxBlock)*r->dsize) {
  213. vtSetError(ETooBig);
  214. return 0;
  215. }
  216. vtLock(r->lk);
  217. depth = sizeToDepth(size, r->psize, r->dsize);
  218. if(size < r->size) {
  219. vtUnlock(r->lk);
  220. return 1;
  221. }
  222. if(depth > r->depth) {
  223. vtSetError(EBadDir);
  224. vtUnlock(r->lk);
  225. return 0;
  226. }
  227. u = r->lump;
  228. vtLock(u->lk);
  229. vtEntryUnpack(&dir, u->data, r->entry);
  230. dir.size = size;
  231. vtEntryPack(&dir, u->data, r->entry);
  232. vtUnlock(u->lk);
  233. r->size = size;
  234. vtUnlock(r->lk);
  235. return 1;
  236. }
  237. int
  238. sourceSetDirSize(Source *r, ulong ds)
  239. {
  240. uvlong size;
  241. size = (uvlong)r->dsize*(ds/r->epb);
  242. size += VtEntrySize*(ds%r->epb);
  243. return sourceSetSize(r, size);
  244. }
  245. ulong
  246. sourceGetDirSize(Source *r)
  247. {
  248. ulong ds;
  249. uvlong size;
  250. size = sourceGetSize(r);
  251. ds = r->epb*(size/r->dsize);
  252. ds += (size%r->dsize)/VtEntrySize;
  253. return ds;
  254. }
  255. ulong
  256. sourceGetNumBlocks(Source *r)
  257. {
  258. return (sourceGetSize(r)+r->dsize-1)/r->dsize;
  259. }
  260. Lump *
  261. sourceWalk(Source *r, ulong block, int readOnly, int *off)
  262. {
  263. int depth;
  264. int i, np;
  265. Lump *u, *v;
  266. int elem[VtPointerDepth+1];
  267. ulong b;
  268. if(r->readOnly && !readOnly) {
  269. vtSetError(EReadOnly);
  270. return nil;
  271. }
  272. vtLock(r->lk);
  273. np = r->psize/VtScoreSize;
  274. b = block;
  275. for(i=0; i<r->depth; i++) {
  276. elem[i] = b % np;
  277. b /= np;
  278. }
  279. if(b != 0) {
  280. vtUnlock(r->lk);
  281. vtSetError(EBadOffset);
  282. return nil;
  283. }
  284. elem[i] = r->entry;
  285. u = lumpIncRef(r->lump);
  286. depth = r->depth;
  287. *off = elem[0];
  288. vtUnlock(r->lk);
  289. for(i=depth; i>0; i--) {
  290. v = lumpWalk(u, elem[i], VtPointerType0+i-1, r->psize, readOnly, 0);
  291. lumpDecRef(u, 0);
  292. if(v == nil)
  293. return nil;
  294. u = v;
  295. }
  296. return u;
  297. }
  298. Lump *
  299. sourceGetLump(Source *r, ulong block, int readOnly, int lock)
  300. {
  301. int type, off;
  302. Lump *u, *v;
  303. if(r->readOnly && !readOnly) {
  304. vtSetError(EReadOnly);
  305. return nil;
  306. }
  307. if(block == NilBlock) {
  308. vtSetError(ENilBlock);
  309. return nil;
  310. }
  311. if(0)fprint(2, "%s: sourceGetLump: %V:%d %lud\n", argv0, r->lump->score, r->entry, block);
  312. u = sourceWalk(r, block, readOnly, &off);
  313. if(u == nil)
  314. return nil;
  315. if(r->dir)
  316. type = VtDirType;
  317. else
  318. type = VtDataType;
  319. v = lumpWalk(u, off, type, r->dsize, readOnly, lock);
  320. lumpDecRef(u, 0);
  321. return v;
  322. }
  323. void
  324. sourceFree(Source *k)
  325. {
  326. if(k == nil)
  327. return;
  328. lumpDecRef(k->lump, 0);
  329. vtLockFree(k->lk);
  330. memset(k, ~0, sizeof(*k));
  331. vtMemFree(k);
  332. }