hash_upgrade.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:7k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996, 1997, 1998, 1999, 2000
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: hash_upgrade.c,v 11.25 2000/12/14 19:18:32 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <limits.h>
  14. #include <string.h>
  15. #endif
  16. #include "db_int.h"
  17. #include "db_page.h"
  18. #include "db_swap.h"
  19. #include "hash.h"
  20. #include "db_upgrade.h"
  21. /*
  22.  * __ham_30_hashmeta --
  23.  *      Upgrade the database from version 4/5 to version 6.
  24.  *
  25.  * PUBLIC: int __ham_30_hashmeta __P((DB *, char *, u_int8_t *));
  26.  */
  27. int
  28. __ham_30_hashmeta(dbp, real_name, obuf)
  29. DB *dbp;
  30. char *real_name;
  31. u_int8_t *obuf;
  32. {
  33. DB_ENV *dbenv;
  34. HASHHDR *oldmeta;
  35. HMETA30 newmeta;
  36. u_int32_t *o_spares, *n_spares;
  37. u_int32_t fillf, maxb, nelem;
  38. int i, max_entry, ret;
  39. dbenv = dbp->dbenv;
  40. memset(&newmeta, 0, sizeof(newmeta));
  41. oldmeta = (HASHHDR *)obuf;
  42. /*
  43.  * The first 32 bytes are similar.  The only change is the version
  44.  * and that we removed the ovfl_point and have the page type now.
  45.  */
  46. newmeta.dbmeta.lsn = oldmeta->lsn;
  47. newmeta.dbmeta.pgno = oldmeta->pgno;
  48. newmeta.dbmeta.magic = oldmeta->magic;
  49. newmeta.dbmeta.version = 6;
  50. newmeta.dbmeta.pagesize = oldmeta->pagesize;
  51. newmeta.dbmeta.type = P_HASHMETA;
  52. /* Move flags */
  53. newmeta.dbmeta.flags = oldmeta->flags;
  54. /* Copy the free list, which has changed its name but works the same. */
  55. newmeta.dbmeta.free = oldmeta->last_freed;
  56. /* Copy: max_bucket, high_mask, low-mask, ffactor, nelem, h_charkey */
  57. newmeta.max_bucket = oldmeta->max_bucket;
  58. newmeta.high_mask = oldmeta->high_mask;
  59. newmeta.low_mask = oldmeta->low_mask;
  60. newmeta.ffactor = oldmeta->ffactor;
  61. newmeta.nelem = oldmeta->nelem;
  62. newmeta.h_charkey = oldmeta->h_charkey;
  63. /*
  64.  * There was a bug in 2.X versions where the nelem could go negative.
  65.  * In general, this is considered "bad."  If it does go negative
  66.  * (that is, very large and positive), we'll die trying to dump and
  67.  * load this database.  So, let's see if we can fix it here.
  68.  */
  69. nelem = newmeta.nelem;
  70. fillf = newmeta.ffactor;
  71. maxb = newmeta.max_bucket;
  72. if ((fillf != 0 && fillf * maxb < 2 * nelem) ||
  73.     (fillf == 0 && nelem > 0x8000000))
  74. newmeta.nelem = 0;
  75. /*
  76.  * We now have to convert the spares array.  The old spares array
  77.  * contained the total number of extra pages allocated prior to
  78.  * the bucket that begins the next doubling.  The new spares array
  79.  * contains the page number of the first bucket in the next doubling
  80.  * MINUS the bucket number of that bucket.
  81.  */
  82. o_spares = oldmeta->spares;
  83. n_spares = newmeta.spares;
  84. max_entry = __db_log2(maxb + 1);   /* highest spares entry in use */
  85. n_spares[0] = 1;
  86. for (i = 1; i < NCACHED && i <= max_entry; i++)
  87. n_spares[i] = 1 + o_spares[i - 1];
  88. /* Replace the unique ID. */
  89. if ((ret = __os_fileid(dbenv, real_name, 1, newmeta.dbmeta.uid)) != 0)
  90. return (ret);
  91. /* Overwrite the original. */
  92. memcpy(oldmeta, &newmeta, sizeof(newmeta));
  93. return (0);
  94. }
  95. /*
  96.  * __ham_30_sizefix --
  97.  * Make sure that all hash pages belonging to the current
  98.  * hash doubling are within the bounds of the file.
  99.  *
  100.  * PUBLIC: int __ham_30_sizefix __P((DB *, DB_FH *, char *, u_int8_t *));
  101.  */
  102. int
  103. __ham_30_sizefix(dbp, fhp, realname, metabuf)
  104. DB *dbp;
  105. DB_FH *fhp;
  106. char *realname;
  107. u_int8_t *metabuf;
  108. {
  109. u_int8_t buf[DB_MAX_PGSIZE];
  110. DB_ENV *dbenv;
  111. HMETA30 *meta;
  112. db_pgno_t last_actual, last_desired;
  113. int ret;
  114. size_t nw;
  115. u_int32_t pagesize;
  116. dbenv = dbp->dbenv;
  117. memset(buf, 0, DB_MAX_PGSIZE);
  118. meta = (HMETA30 *)metabuf;
  119. pagesize = meta->dbmeta.pagesize;
  120. /*
  121.  * Get the last page number.  To do this, we'll need dbp->pgsize
  122.  * to be set right, so slam it into place.
  123.  */
  124. dbp->pgsize = pagesize;
  125. if ((ret = __db_lastpgno(dbp, realname, fhp, &last_actual)) != 0)
  126. return (ret);
  127. /*
  128.  * The last bucket in the doubling is equal to high_mask;  calculate
  129.  * the page number that implies.
  130.  */
  131. last_desired = BS_TO_PAGE(meta->high_mask, meta->spares);
  132. /*
  133.  * If last_desired > last_actual, we need to grow the file.  Write
  134.  * a zeroed page where last_desired would go.
  135.  */
  136. if (last_desired > last_actual) {
  137. if ((ret = __os_seek(dbenv,
  138.     fhp, pagesize, last_desired, 0, 0, DB_OS_SEEK_SET)) != 0)
  139. return (ret);
  140. if ((ret = __os_write(dbenv, fhp, buf, pagesize, &nw)) != 0)
  141. return (ret);
  142. if (nw != pagesize) {
  143. __db_err(dbenv, "Short write during upgrade");
  144. return (EIO);
  145. }
  146. }
  147. return (0);
  148. }
  149. /*
  150.  * __ham_31_hashmeta --
  151.  *      Upgrade the database from version 6 to version 7.
  152.  *
  153.  * PUBLIC: int __ham_31_hashmeta
  154.  * PUBLIC:      __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *));
  155.  */
  156. int
  157. __ham_31_hashmeta(dbp, real_name, flags, fhp, h, dirtyp)
  158. DB *dbp;
  159. char *real_name;
  160. u_int32_t flags;
  161. DB_FH *fhp;
  162. PAGE *h;
  163. int *dirtyp;
  164. {
  165. HMETA31 *newmeta;
  166. HMETA30 *oldmeta;
  167. COMPQUIET(dbp, NULL);
  168. COMPQUIET(real_name, NULL);
  169. COMPQUIET(fhp, NULL);
  170. newmeta = (HMETA31 *)h;
  171. oldmeta = (HMETA30 *)h;
  172. /*
  173.  * Copy the fields down the page.
  174.  * The fields may overlap so start at the bottom and use memmove().
  175.  */
  176. memmove(newmeta->spares, oldmeta->spares, sizeof(oldmeta->spares));
  177. newmeta->h_charkey = oldmeta->h_charkey;
  178. newmeta->nelem = oldmeta->nelem;
  179. newmeta->ffactor = oldmeta->ffactor;
  180. newmeta->low_mask = oldmeta->low_mask;
  181. newmeta->high_mask = oldmeta->high_mask;
  182. newmeta->max_bucket = oldmeta->max_bucket;
  183. memmove(newmeta->dbmeta.uid,
  184.     oldmeta->dbmeta.uid, sizeof(oldmeta->dbmeta.uid));
  185. newmeta->dbmeta.flags = oldmeta->dbmeta.flags;
  186. newmeta->dbmeta.record_count = 0;
  187. newmeta->dbmeta.key_count = 0;
  188. ZERO_LSN(newmeta->dbmeta.unused3);
  189. /* Update the version. */
  190. newmeta->dbmeta.version = 7;
  191. /* Upgrade the flags. */
  192. if (LF_ISSET(DB_DUPSORT))
  193. F_SET(&newmeta->dbmeta, DB_HASH_DUPSORT);
  194. *dirtyp = 1;
  195. return (0);
  196. }
  197. /*
  198.  * __ham_31_hash --
  199.  *      Upgrade the database hash leaf pages.
  200.  *
  201.  * PUBLIC: int __ham_31_hash
  202.  * PUBLIC:      __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *));
  203.  */
  204. int
  205. __ham_31_hash(dbp, real_name, flags, fhp, h, dirtyp)
  206. DB *dbp;
  207. char *real_name;
  208. u_int32_t flags;
  209. DB_FH *fhp;
  210. PAGE *h;
  211. int *dirtyp;
  212. {
  213. HKEYDATA *hk;
  214. db_pgno_t pgno, tpgno;
  215. db_indx_t indx;
  216. int ret;
  217. COMPQUIET(flags, 0);
  218. ret = 0;
  219. for (indx = 0; indx < NUM_ENT(h); indx += 2) {
  220. hk = (HKEYDATA *)H_PAIRDATA(h, indx);
  221. if (HPAGE_PTYPE(hk) == H_OFFDUP) {
  222. memcpy(&pgno, HOFFDUP_PGNO(hk), sizeof(db_pgno_t));
  223. tpgno = pgno;
  224. if ((ret = __db_31_offdup(dbp, real_name, fhp,
  225.     LF_ISSET(DB_DUPSORT) ? 1 : 0, &tpgno)) != 0)
  226. break;
  227. if (pgno != tpgno) {
  228. *dirtyp = 1;
  229. memcpy(HOFFDUP_PGNO(hk),
  230.     &tpgno, sizeof(db_pgno_t));
  231. }
  232. }
  233. }
  234. return (ret);
  235. }