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

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: db_upg.c,v 11.20 2000/12/12 17:35:30 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <string.h>
  14. #endif
  15. #include "db_int.h"
  16. #include "db_page.h"
  17. #include "db_swap.h"
  18. #include "btree.h"
  19. #include "hash.h"
  20. #include "qam.h"
  21. static int (* const func_31_list[P_PAGETYPE_MAX])
  22.     __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)) = {
  23. NULL, /* P_INVALID */
  24. NULL, /* __P_DUPLICATE */
  25. __ham_31_hash, /* P_HASH */
  26. NULL, /* P_IBTREE */
  27. NULL, /* P_IRECNO */
  28. __bam_31_lbtree, /* P_LBTREE */
  29. NULL, /* P_LRECNO */
  30. NULL, /* P_OVERFLOW */
  31. __ham_31_hashmeta, /* P_HASHMETA */
  32. __bam_31_btreemeta, /* P_BTREEMETA */
  33. };
  34. static int __db_page_pass __P((DB *, char *, u_int32_t, int (* const [])
  35.        (DB *, char *, u_int32_t, DB_FH *, PAGE *, int *), DB_FH *));
  36. /*
  37.  * __db_upgrade --
  38.  * Upgrade an existing database.
  39.  *
  40.  * PUBLIC: int __db_upgrade __P((DB *, const char *, u_int32_t));
  41.  */
  42. int
  43. __db_upgrade(dbp, fname, flags)
  44. DB *dbp;
  45. const char *fname;
  46. u_int32_t flags;
  47. {
  48. DB_ENV *dbenv;
  49. DB_FH fh;
  50. size_t n;
  51. int ret, t_ret;
  52. u_int8_t mbuf[256];
  53. char *real_name;
  54. dbenv = dbp->dbenv;
  55. /* Validate arguments. */
  56. if ((ret = __db_fchk(dbenv, "DB->upgrade", flags, DB_DUPSORT)) != 0)
  57. return (ret);
  58. /* Get the real backing file name. */
  59. if ((ret = __db_appname(dbenv,
  60.     DB_APP_DATA, NULL, fname, 0, NULL, &real_name)) != 0)
  61. return (ret);
  62. /* Open the file. */
  63. if ((ret = __os_open(dbenv, real_name, 0, 0, &fh)) != 0) {
  64. __db_err(dbenv, "%s: %s", real_name, db_strerror(ret));
  65. return (ret);
  66. }
  67. /* Initialize the feedback. */
  68. if (dbp->db_feedback != NULL)
  69. dbp->db_feedback(dbp, DB_UPGRADE, 0);
  70. /*
  71.  * Read the metadata page.  We read 256 bytes, which is larger than
  72.  * any access method's metadata page and smaller than any disk sector.
  73.  */
  74. if ((ret = __os_read(dbenv, &fh, mbuf, sizeof(mbuf), &n)) != 0)
  75. goto err;
  76. switch (((DBMETA *)mbuf)->magic) {
  77. case DB_BTREEMAGIC:
  78. switch (((DBMETA *)mbuf)->version) {
  79. case 6:
  80. /*
  81.  * Before V7 not all pages had page types, so we do the
  82.  * single meta-data page by hand.
  83.  */
  84. if ((ret =
  85.     __bam_30_btreemeta(dbp, real_name, mbuf)) != 0)
  86. goto err;
  87. if ((ret = __os_seek(dbenv,
  88.     &fh, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0)
  89. goto err;
  90. if ((ret = __os_write(dbenv, &fh, mbuf, 256, &n)) != 0)
  91. goto err;
  92. /* FALLTHROUGH */
  93. case 7:
  94. /*
  95.  * We need the page size to do more.  Rip it out of
  96.  * the meta-data page.
  97.  */
  98. memcpy(&dbp->pgsize, mbuf + 20, sizeof(u_int32_t));
  99. if ((ret = __db_page_pass(
  100.     dbp, real_name, flags, func_31_list, &fh)) != 0)
  101. goto err;
  102. /* FALLTHROUGH */
  103. case 8:
  104. break;
  105. default:
  106. __db_err(dbenv, "%s: unsupported btree version: %lu",
  107.     real_name, (u_long)((DBMETA *)mbuf)->version);
  108. ret = DB_OLD_VERSION;
  109. goto err;
  110. }
  111. break;
  112. case DB_HASHMAGIC:
  113. switch (((DBMETA *)mbuf)->version) {
  114. case 4:
  115. case 5:
  116. /*
  117.  * Before V6 not all pages had page types, so we do the
  118.  * single meta-data page by hand.
  119.  */
  120. if ((ret =
  121.     __ham_30_hashmeta(dbp, real_name, mbuf)) != 0)
  122. goto err;
  123. if ((ret = __os_seek(dbenv,
  124.     &fh, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0)
  125. goto err;
  126. if ((ret = __os_write(dbenv, &fh, mbuf, 256, &n)) != 0)
  127. goto err;
  128. /*
  129.  * Before V6, we created hash pages one by one as they
  130.  * were needed, using hashhdr.ovfl_point to reserve
  131.  * a block of page numbers for them.  A consequence
  132.  * of this was that, if no overflow pages had been
  133.  * created, the current doubling might extend past
  134.  * the end of the database file.
  135.  *
  136.  * In DB 3.X, we now create all the hash pages
  137.  * belonging to a doubling atomicly;  it's not
  138.  * safe to just save them for later, because when
  139.  * we create an overflow page we'll just create
  140.  * a new last page (whatever that may be).  Grow
  141.  * the database to the end of the current doubling.
  142.  */
  143. if ((ret =
  144.     __ham_30_sizefix(dbp, &fh, real_name, mbuf)) != 0)
  145. goto err;
  146. /* FALLTHROUGH */
  147. case 6:
  148. /*
  149.  * We need the page size to do more.  Rip it out of
  150.  * the meta-data page.
  151.  */
  152. memcpy(&dbp->pgsize, mbuf + 20, sizeof(u_int32_t));
  153. if ((ret = __db_page_pass(
  154.     dbp, real_name, flags, func_31_list, &fh)) != 0)
  155. goto err;
  156. /* FALLTHROUGH */
  157. case 7:
  158. break;
  159. default:
  160. __db_err(dbenv, "%s: unsupported hash version: %lu",
  161.     real_name, (u_long)((DBMETA *)mbuf)->version);
  162. ret = DB_OLD_VERSION;
  163. goto err;
  164. }
  165. break;
  166. case DB_QAMMAGIC:
  167. switch (((DBMETA *)mbuf)->version) {
  168. case 1:
  169. /*
  170.  * If we're in a Queue database, the only page that
  171.  * needs upgrading is the meta-database page, don't
  172.  * bother with a full pass.
  173.  */
  174. if ((ret = __qam_31_qammeta(dbp, real_name, mbuf)) != 0)
  175. return (ret);
  176. /* FALLTHROUGH */
  177. case 2:
  178. if ((ret = __qam_32_qammeta(dbp, real_name, mbuf)) != 0)
  179. return (ret);
  180. if ((ret = __os_seek(dbenv,
  181.     &fh, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0)
  182. goto err;
  183. if ((ret = __os_write(dbenv, &fh, mbuf, 256, &n)) != 0)
  184. goto err;
  185. /* FALLTHROUGH */
  186. case 3:
  187. break;
  188. default:
  189. __db_err(dbenv, "%s: unsupported queue version: %lu",
  190.     real_name, (u_long)((DBMETA *)mbuf)->version);
  191. ret = DB_OLD_VERSION;
  192. goto err;
  193. }
  194. break;
  195. default:
  196. M_32_SWAP(((DBMETA *)mbuf)->magic);
  197. switch (((DBMETA *)mbuf)->magic) {
  198. case DB_BTREEMAGIC:
  199. case DB_HASHMAGIC:
  200. case DB_QAMMAGIC:
  201. __db_err(dbenv,
  202. "%s: DB->upgrade only supported on native byte-order systems",
  203.     real_name);
  204. break;
  205. default:
  206. __db_err(dbenv,
  207.     "%s: unrecognized file type", real_name);
  208. break;
  209. }
  210. ret = EINVAL;
  211. goto err;
  212. }
  213. ret = __os_fsync(dbenv, &fh);
  214. err: if ((t_ret = __os_closehandle(&fh)) != 0 && ret == 0)
  215. ret = t_ret;
  216. __os_freestr(real_name);
  217. /* We're done. */
  218. if (dbp->db_feedback != NULL)
  219. dbp->db_feedback(dbp, DB_UPGRADE, 100);
  220. return (ret);
  221. }
  222. /*
  223.  * __db_page_pass --
  224.  * Walk the pages of the database, upgrading whatever needs it.
  225.  */
  226. static int
  227. __db_page_pass(dbp, real_name, flags, fl, fhp)
  228. DB *dbp;
  229. char *real_name;
  230. u_int32_t flags;
  231. int (* const fl[P_PAGETYPE_MAX])
  232.     __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *));
  233. DB_FH *fhp;
  234. {
  235. DB_ENV *dbenv;
  236. PAGE *page;
  237. db_pgno_t i, pgno_last;
  238. size_t n;
  239. int dirty, ret;
  240. dbenv = dbp->dbenv;
  241. /* Determine the last page of the file. */
  242. if ((ret = __db_lastpgno(dbp, real_name, fhp, &pgno_last)) != 0)
  243. return (ret);
  244. /* Allocate memory for a single page. */
  245. if ((ret = __os_malloc(dbenv, dbp->pgsize, NULL, &page)) != 0)
  246. return (ret);
  247. /* Walk the file, calling the underlying conversion functions. */
  248. for (i = 0; i < pgno_last; ++i) {
  249. if (dbp->db_feedback != NULL)
  250. dbp->db_feedback(dbp, DB_UPGRADE, (i * 100)/pgno_last);
  251. if ((ret = __os_seek(dbenv,
  252.     fhp, dbp->pgsize, i, 0, 0, DB_OS_SEEK_SET)) != 0)
  253. break;
  254. if ((ret = __os_read(dbenv, fhp, page, dbp->pgsize, &n)) != 0)
  255. break;
  256. dirty = 0;
  257. if (fl[TYPE(page)] != NULL && (ret = fl[TYPE(page)]
  258.     (dbp, real_name, flags, fhp, page, &dirty)) != 0)
  259. break;
  260. if (dirty) {
  261. if ((ret = __os_seek(dbenv,
  262.     fhp, dbp->pgsize, i, 0, 0, DB_OS_SEEK_SET)) != 0)
  263. break;
  264. if ((ret = __os_write(dbenv,
  265.     fhp, page, dbp->pgsize, &n)) != 0)
  266. break;
  267. }
  268. }
  269. __os_free(page, dbp->pgsize);
  270. return (ret);
  271. }
  272. /*
  273.  * __db_lastpgno --
  274.  * Return the current last page number of the file.
  275.  *
  276.  * PUBLIC: int __db_lastpgno __P((DB *, char *, DB_FH *, db_pgno_t *));
  277.  */
  278. int
  279. __db_lastpgno(dbp, real_name, fhp, pgno_lastp)
  280. DB *dbp;
  281. char *real_name;
  282. DB_FH *fhp;
  283. db_pgno_t *pgno_lastp;
  284. {
  285. DB_ENV *dbenv;
  286. db_pgno_t pgno_last;
  287. u_int32_t mbytes, bytes;
  288. int ret;
  289. dbenv = dbp->dbenv;
  290. if ((ret = __os_ioinfo(dbenv,
  291.     real_name, fhp, &mbytes, &bytes, NULL)) != 0) {
  292. __db_err(dbenv, "%s: %s", real_name, db_strerror(ret));
  293. return (ret);
  294. }
  295. /* Page sizes have to be a power-of-two. */
  296. if (bytes % dbp->pgsize != 0) {
  297. __db_err(dbenv,
  298.     "%s: file size not a multiple of the pagesize", real_name);
  299. return (EINVAL);
  300. }
  301. pgno_last = mbytes * (MEGABYTE / dbp->pgsize);
  302. pgno_last += bytes / dbp->pgsize;
  303. *pgno_lastp = pgno_last;
  304. return (0);
  305. }