mkhash.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include <ndb.h>
  5. /*
  6. * make the hash table completely in memory and then write as a file
  7. */
  8. uchar *ht;
  9. ulong hlen;
  10. Ndb *db;
  11. ulong nextchain;
  12. char*
  13. syserr(void)
  14. {
  15. static char buf[ERRMAX];
  16. errstr(buf, sizeof buf);
  17. return buf;
  18. }
  19. void
  20. enter(char *val, ulong dboff)
  21. {
  22. ulong h;
  23. uchar *last;
  24. ulong ptr;
  25. h = ndbhash(val, hlen);
  26. h *= NDBPLEN;
  27. last = &ht[h];
  28. ptr = NDBGETP(last);
  29. if(ptr == NDBNAP){
  30. NDBPUTP(dboff, last);
  31. return;
  32. }
  33. if(ptr & NDBCHAIN){
  34. /* walk the chain to the last entry */
  35. for(;;){
  36. ptr &= ~NDBCHAIN;
  37. last = &ht[ptr+NDBPLEN];
  38. ptr = NDBGETP(last);
  39. if(ptr == NDBNAP){
  40. NDBPUTP(dboff, last);
  41. return;
  42. }
  43. if(!(ptr & NDBCHAIN)){
  44. NDBPUTP(nextchain|NDBCHAIN, last);
  45. break;
  46. }
  47. }
  48. } else
  49. NDBPUTP(nextchain|NDBCHAIN, last);
  50. /* add a chained entry */
  51. NDBPUTP(ptr, &ht[nextchain]);
  52. NDBPUTP(dboff, &ht[nextchain + NDBPLEN]);
  53. nextchain += 2*NDBPLEN;
  54. }
  55. uchar nbuf[16*1024];
  56. void
  57. main(int argc, char **argv)
  58. {
  59. Ndbtuple *t, *nt;
  60. int n;
  61. Dir *d;
  62. uchar buf[8];
  63. char file[128];
  64. int fd;
  65. ulong off;
  66. uchar *p;
  67. if(argc != 3){
  68. fprint(2, "mkhash: usage file attribute\n");
  69. exits("usage");
  70. }
  71. db = ndbopen(argv[1]);
  72. if(db == 0){
  73. fprint(2, "mkhash: can't open %s\n", argv[1]);
  74. exits(syserr());
  75. }
  76. /* try a bigger than normal buffer */
  77. Binits(&db->b, Bfildes(&db->b), OREAD, nbuf, sizeof(nbuf));
  78. /* count entries to calculate hash size */
  79. n = 0;
  80. while(nt = ndbparse(db)){
  81. for(t = nt; t; t = t->entry){
  82. if(strcmp(t->attr, argv[2]) == 0)
  83. n++;
  84. }
  85. ndbfree(nt);
  86. }
  87. /* allocate an array large enough for worst case */
  88. hlen = 2*n+1;
  89. n = hlen*NDBPLEN + hlen*2*NDBPLEN;
  90. ht = mallocz(n, 1);
  91. if(ht == 0){
  92. fprint(2, "mkhash: not enough memory\n");
  93. exits(syserr());
  94. }
  95. for(p = ht; p < &ht[n]; p += NDBPLEN)
  96. NDBPUTP(NDBNAP, p);
  97. nextchain = hlen*NDBPLEN;
  98. /* create the in core hash table */
  99. Bseek(&db->b, 0, 0);
  100. off = 0;
  101. while(nt = ndbparse(db)){
  102. for(t = nt; t; t = t->entry){
  103. if(strcmp(t->attr, argv[2]) == 0)
  104. enter(t->val, off);
  105. }
  106. ndbfree(nt);
  107. off = Boffset(&db->b);
  108. }
  109. /* create the hash file */
  110. snprint(file, sizeof(file), "%s.%s", argv[1], argv[2]);
  111. fd = create(file, ORDWR, 0664);
  112. if(fd < 0){
  113. fprint(2, "mkhash: can't create %s\n", file);
  114. exits(syserr());
  115. }
  116. NDBPUTUL(db->mtime, buf);
  117. NDBPUTUL(hlen, buf+NDBULLEN);
  118. if(write(fd, buf, NDBHLEN) != NDBHLEN){
  119. fprint(2, "mkhash: writing %s\n", file);
  120. exits(syserr());
  121. }
  122. if(write(fd, ht, nextchain) != nextchain){
  123. fprint(2, "mkhash: writing %s\n", file);
  124. exits(syserr());
  125. }
  126. close(fd);
  127. /* make sure file didn't change while we were making the hash */
  128. d = dirstat(argv[1]);
  129. if(d == nil || d->qid.path != db->qid.path
  130. || d->qid.vers != db->qid.vers){
  131. fprint(2, "mkhash: %s changed underfoot\n", argv[1]);
  132. remove(file);
  133. exits("changed");
  134. }
  135. exits(0);
  136. }