dbm.b 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. implement Dbm;
  2. # Copyright © Caldera International Inc. 2001-2002. All rights reserved.
  3. # Limbo transliteration (with amendment) Copyright © 2004 Vita Nuova Holdings Limited.
  4. include "sys.m";
  5. sys: Sys;
  6. OREAD, OWRITE, ORDWR: import Sys;
  7. include "dbm.m";
  8. BYTESIZ: con 8; # bits
  9. SHORTSIZ: con 2; # bytes
  10. PBLKSIZ: con 512;
  11. DBLKSIZ: con 8192; # was 4096
  12. init()
  13. {
  14. sys = load Sys Sys->PATH;
  15. }
  16. Dbf.create(file: string, mode: int): ref Dbf
  17. {
  18. pf := sys->create(file+".pag", ORDWR, mode);
  19. if(pf == nil)
  20. return nil;
  21. df := sys->create(file+".dir", ORDWR, mode);
  22. if(df == nil)
  23. return nil;
  24. return alloc(pf, df, ORDWR);
  25. }
  26. Dbf.open(file: string, flags: int): ref Dbf
  27. {
  28. if((flags & 3) == OWRITE)
  29. flags = (flags & ~3) | ORDWR;
  30. pf := sys->open(file+".pag", flags);
  31. if(pf == nil)
  32. return nil;
  33. df := sys->open(file+".dir", flags);
  34. if(df == nil)
  35. return nil;
  36. return alloc(pf, df, flags);
  37. }
  38. alloc(pf: ref Sys->FD, df: ref Sys->FD, flags: int): ref Dbf
  39. {
  40. db := ref Dbf;
  41. db.pagf = pf;
  42. db.dirf = df;
  43. db.flags = flags & 3;
  44. db.maxbno = 0;
  45. db.bitno = 0;
  46. db.hmask = 0;
  47. db.blkno = 0;
  48. db.pagbno = -1;
  49. db.pagbuf = array[PBLKSIZ] of byte;
  50. db.dirbno = -1;
  51. db.dirbuf = array[DBLKSIZ] of byte;
  52. (ok, d) := sys->fstat(db.dirf);
  53. if(ok < 0)
  54. d.length = big 0;
  55. db.maxbno = int (d.length*big BYTESIZ - big 1);
  56. return db;
  57. }
  58. Dbf.flush(db: self ref Dbf)
  59. {
  60. db.pagbno = db.dirbno = -1;
  61. }
  62. Dbf.isrdonly(db: self ref Dbf): int
  63. {
  64. return db.flags == OREAD;
  65. }
  66. Dbf.fetch(db: self ref Dbf, key: Datum): Datum
  67. {
  68. access(db, calchash(key));
  69. for(i:=0;; i+=2){
  70. item := makdatum(db.pagbuf, i);
  71. if(item == nil)
  72. return item;
  73. if(cmpdatum(key, item) == 0){
  74. item = makdatum(db.pagbuf, i+1);
  75. if(item == nil){
  76. sys->fprint(sys->fildes(2), "dbm: items not in pairs\n");
  77. raise "dbm: items not in pairs";
  78. }
  79. return item;
  80. }
  81. }
  82. }
  83. Dbf.delete(db: self ref Dbf, key: Datum): int
  84. {
  85. if(db.isrdonly())
  86. return -1;
  87. access(db, calchash(key));
  88. for(i:=0;; i+=2){
  89. item := makdatum(db.pagbuf, i);
  90. if(item == nil)
  91. return -1;
  92. if(cmpdatum(key, item) == 0){
  93. delitem(db.pagbuf, i);
  94. delitem(db.pagbuf, i);
  95. break;
  96. }
  97. }
  98. sys->seek(db.pagf, big db.blkno*big PBLKSIZ, 0);
  99. write(db.pagf, db.pagbuf, PBLKSIZ);
  100. db.pagbno = db.blkno;
  101. return 0;
  102. }
  103. Dbf.store(db: self ref Dbf, key: Datum, dat: Datum, replace: int): int
  104. {
  105. if(db.isrdonly())
  106. return -1;
  107. for(;;){
  108. access(db, calchash(key));
  109. for(i:=0;; i+=2){
  110. item := makdatum(db.pagbuf, i);
  111. if(item == nil)
  112. break;
  113. if(cmpdatum(key, item) == 0){
  114. if(!replace)
  115. return 1;
  116. delitem(db.pagbuf, i);
  117. delitem(db.pagbuf, i);
  118. break;
  119. }
  120. }
  121. i = additem(db.pagbuf, key);
  122. if(i >= 0){
  123. if(additem(db.pagbuf, dat) >= 0)
  124. break;
  125. delitem(db.pagbuf, i);
  126. }
  127. if(!split(db, key, dat))
  128. return -1;
  129. }
  130. sys->seek(db.pagf, big db.blkno*big PBLKSIZ, 0);
  131. write(db.pagf, db.pagbuf, PBLKSIZ);
  132. db.pagbno = db.blkno;
  133. return 0;
  134. }
  135. split(db: ref Dbf, key: Datum, dat: Datum): int
  136. {
  137. if(len key+len dat+3*SHORTSIZ >= PBLKSIZ)
  138. return 0;
  139. ovfbuf := array[PBLKSIZ] of {* => byte 0};
  140. for(i:=0;;){
  141. item := makdatum(db.pagbuf, i);
  142. if(item == nil)
  143. break;
  144. if(calchash(item) & (db.hmask+1)){
  145. additem(ovfbuf, item);
  146. delitem(db.pagbuf, i);
  147. item = makdatum(db.pagbuf, i);
  148. if(item == nil){
  149. sys->fprint(sys->fildes(2), "dbm: split not paired\n");
  150. raise "dbm: split not paired";
  151. #break;
  152. }
  153. additem(ovfbuf, item);
  154. delitem(db.pagbuf, i);
  155. continue;
  156. }
  157. i += 2;
  158. }
  159. sys->seek(db.pagf, big db.blkno*big PBLKSIZ, 0);
  160. write(db.pagf, db.pagbuf, PBLKSIZ);
  161. db.pagbno = db.blkno;
  162. sys->seek(db.pagf, (big db.blkno+big db.hmask+big 1)*big PBLKSIZ, 0);
  163. write(db.pagf, ovfbuf, PBLKSIZ);
  164. setbit(db);
  165. return 1;
  166. }
  167. Dbf.firstkey(db: self ref Dbf): Datum
  168. {
  169. return copy(firsthash(db, 0));
  170. }
  171. Dbf.nextkey(db: self ref Dbf, key: Datum): Datum
  172. {
  173. hash := calchash(key);
  174. access(db, hash);
  175. item, bitem: Datum;
  176. for(i:=0;; i+=2){
  177. item = makdatum(db.pagbuf, i);
  178. if(item == nil)
  179. break;
  180. if(cmpdatum(key, item) <= 0)
  181. continue;
  182. if(bitem == nil || cmpdatum(bitem, item) < 0)
  183. bitem = item;
  184. }
  185. if(bitem != nil)
  186. return copy(bitem);
  187. hash = hashinc(db, hash);
  188. if(hash == 0)
  189. return copy(item);
  190. return copy(firsthash(db, hash));
  191. }
  192. firsthash(db: ref Dbf, hash: int): Datum
  193. {
  194. for(;;){
  195. access(db, hash);
  196. bitem := makdatum(db.pagbuf, 0);
  197. item: Datum;
  198. for(i:=2;; i+=2){
  199. item = makdatum(db.pagbuf, i);
  200. if(item == nil)
  201. break;
  202. if(cmpdatum(bitem, item) < 0)
  203. bitem = item;
  204. }
  205. if(bitem != nil)
  206. return bitem;
  207. hash = hashinc(db, hash);
  208. if(hash == 0)
  209. return item;
  210. }
  211. }
  212. access(db: ref Dbf, hash: int)
  213. {
  214. for(db.hmask=0;; db.hmask=(db.hmask<<1)+1){
  215. db.blkno = hash & db.hmask;
  216. db.bitno = db.blkno + db.hmask;
  217. if(getbit(db) == 0)
  218. break;
  219. }
  220. if(db.blkno != db.pagbno){
  221. sys->seek(db.pagf, big db.blkno * big PBLKSIZ, 0);
  222. read(db.pagf, db.pagbuf, PBLKSIZ);
  223. chkblk(db.pagbuf);
  224. db.pagbno = db.blkno;
  225. }
  226. }
  227. getbit(db: ref Dbf): int
  228. {
  229. if(db.bitno > db.maxbno)
  230. return 0;
  231. n := db.bitno % BYTESIZ;
  232. bn := db.bitno / BYTESIZ;
  233. i := bn % DBLKSIZ;
  234. b := bn / DBLKSIZ;
  235. if(b != db.dirbno){
  236. sys->seek(db.dirf, big b * big DBLKSIZ, 0);
  237. read(db.dirf, db.dirbuf, DBLKSIZ);
  238. db.dirbno = b;
  239. }
  240. if(int db.dirbuf[i] & (1<<n))
  241. return 1;
  242. return 0;
  243. }
  244. setbit(db: ref Dbf)
  245. {
  246. if(db.bitno > db.maxbno){
  247. db.maxbno = db.bitno;
  248. getbit(db);
  249. }
  250. n := db.bitno % BYTESIZ;
  251. bn := db.bitno / BYTESIZ;
  252. i := bn % DBLKSIZ;
  253. b := bn / DBLKSIZ;
  254. db.dirbuf[i] |= byte (1<<n);
  255. sys->seek(db.dirf, big b * big DBLKSIZ, 0);
  256. write(db.dirf, db.dirbuf, DBLKSIZ);
  257. db.dirbno = b;
  258. }
  259. makdatum(buf: array of byte, n: int): Datum
  260. {
  261. ne := GETS(buf, 0);
  262. if(n < 0 || n >= ne)
  263. return nil;
  264. t := PBLKSIZ;
  265. if(n > 0)
  266. t = GETS(buf, n+1-1);
  267. v := GETS(buf, n+1);
  268. return buf[v: t]; # size is t-v
  269. }
  270. cmpdatum(d1: Datum, d2: Datum): int
  271. {
  272. n := len d1;
  273. if(n != len d2)
  274. return n - len d2;
  275. if(n == 0)
  276. return 0;
  277. for(i := 0; i < len d1; i++)
  278. if(d1[i] != d2[i])
  279. return int d1[i] - int d2[i];
  280. return 0;
  281. }
  282. copy(d: Datum): Datum
  283. {
  284. if(d == nil)
  285. return nil;
  286. a := array[len d] of byte;
  287. a[0:] = d;
  288. return a;
  289. }
  290. # ken's
  291. #
  292. # 055,043,036,054,063,014,004,005,
  293. # 010,064,077,000,035,027,025,071,
  294. #
  295. hitab := array[16] of {
  296. 61, 57, 53, 49, 45, 41, 37, 33,
  297. 29, 25, 21, 17, 13, 9, 5, 1,
  298. };
  299. hltab := array[64] of {
  300. 8r6100151277,8r6106161736,8r6452611562,8r5001724107,
  301. 8r2614772546,8r4120731531,8r4665262210,8r7347467531,
  302. 8r6735253126,8r6042345173,8r3072226605,8r1464164730,
  303. 8r3247435524,8r7652510057,8r1546775256,8r5714532133,
  304. 8r6173260402,8r7517101630,8r2431460343,8r1743245566,
  305. 8r0261675137,8r2433103631,8r3421772437,8r4447707466,
  306. 8r4435620103,8r3757017115,8r3641531772,8r6767633246,
  307. 8r2673230344,8r0260612216,8r4133454451,8r0615531516,
  308. 8r6137717526,8r2574116560,8r2304023373,8r7061702261,
  309. 8r5153031405,8r5322056705,8r7401116734,8r6552375715,
  310. 8r6165233473,8r5311063631,8r1212221723,8r1052267235,
  311. 8r6000615237,8r1075222665,8r6330216006,8r4402355630,
  312. 8r1451177262,8r2000133436,8r6025467062,8r7121076461,
  313. 8r3123433522,8r1010635225,8r1716177066,8r5161746527,
  314. 8r1736635071,8r6243505026,8r3637211610,8r1756474365,
  315. 8r4723077174,8r3642763134,8r5750130273,8r3655541561,
  316. };
  317. hashinc(db: ref Dbf, hash: int): int
  318. {
  319. hash &= db.hmask;
  320. bit := db.hmask+1;
  321. for(;;){
  322. bit >>= 1;
  323. if(bit == 0)
  324. return 0;
  325. if((hash&bit) == 0)
  326. return hash|bit;
  327. hash &= ~bit;
  328. }
  329. }
  330. calchash(item: Datum): int
  331. {
  332. hashl := 0;
  333. hashi := 0;
  334. for(i:=0; i<len item; i++){
  335. f := int item[i];
  336. for(j:=0; j<BYTESIZ; j+=4){
  337. hashi += hitab[f&16rF];
  338. hashl += hltab[hashi&16r3F];
  339. f >>= 4;
  340. }
  341. }
  342. return hashl;
  343. }
  344. delitem(buf: array of byte, n: int)
  345. {
  346. ne := GETS(buf, 0);
  347. if(n < 0 || n >= ne){
  348. sys->fprint(sys->fildes(2), "dbm: bad delitem\n");
  349. raise "dbm: bad delitem";
  350. }
  351. i1 := GETS(buf, n+1);
  352. i2 := PBLKSIZ;
  353. if(n > 0)
  354. i2 = GETS(buf, n+1-1);
  355. i3 := GETS(buf, ne+1-1);
  356. if(i2 > i1)
  357. while(i1 > i3){
  358. i1--;
  359. i2--;
  360. buf[i2] = buf[i1];
  361. buf[i1] = byte 0;
  362. }
  363. i2 -= i1;
  364. for(i1=n+1; i1<ne; i1++)
  365. PUTS(buf, i1+1-1, GETS(buf, i1+1) + i2);
  366. PUTS(buf, 0, ne-1);
  367. PUTS(buf, ne, 0);
  368. }
  369. additem(buf: array of byte, item: Datum): int
  370. {
  371. i1 := PBLKSIZ;
  372. ne := GETS(buf, 0);
  373. if(ne > 0)
  374. i1 = GETS(buf, ne+1-1);
  375. i1 -= len item;
  376. i2 := (ne+2) * SHORTSIZ;
  377. if(i1 <= i2)
  378. return -1;
  379. PUTS(buf, ne+1, i1);
  380. buf[i1:] = item;
  381. PUTS(buf, 0, ne+1);
  382. return ne;
  383. }
  384. chkblk(buf: array of byte)
  385. {
  386. t := PBLKSIZ;
  387. ne := GETS(buf, 0);
  388. for(i:=0; i<ne; i++){
  389. v := GETS(buf, i+1);
  390. if(v > t)
  391. badblk();
  392. t = v;
  393. }
  394. if(t < (ne+1)*SHORTSIZ)
  395. badblk();
  396. }
  397. read(fd: ref Sys->FD, buf: array of byte, n: int)
  398. {
  399. nr := sys->read(fd, buf, n);
  400. if(nr == 0){
  401. for(i := 0; i < len buf; i++)
  402. buf[i] = byte 0;
  403. }else if(nr != n)
  404. raise "dbm: read error: "+sys->sprint("%r");
  405. }
  406. write(fd: ref Sys->FD, buf: array of byte, n: int)
  407. {
  408. if(sys->write(fd, buf, n) != n)
  409. raise "dbm: write error: "+sys->sprint("%r");
  410. }
  411. badblk()
  412. {
  413. sys->fprint(sys->fildes(2), "dbm: bad block\n");
  414. raise "dbm: bad block";
  415. }
  416. GETS(buf: array of byte, sh: int): int
  417. {
  418. sh *= SHORTSIZ;
  419. return (int buf[sh]<<8) | int buf[sh+1];
  420. }
  421. PUTS(buf: array of byte, sh: int, v: int)
  422. {
  423. sh *= SHORTSIZ;
  424. buf[sh] = byte (v>>8);
  425. buf[sh+1] = byte v;
  426. }