db_upg.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:8k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996-2002
  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.29 2002/03/27 18:59:04 krinsky 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 "dbinc/db_page.h"
  17. #include "dbinc/db_swap.h"
  18. #include "dbinc/btree.h"
  19. #include "dbinc/hash.h"
  20. #include "dbinc/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, 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. case 9:
  105. break;
  106. default:
  107. __db_err(dbenv, "%s: unsupported btree version: %lu",
  108.     real_name, (u_long)((DBMETA *)mbuf)->version);
  109. ret = DB_OLD_VERSION;
  110. goto err;
  111. }
  112. break;
  113. case DB_HASHMAGIC:
  114. switch (((DBMETA *)mbuf)->version) {
  115. case 4:
  116. case 5:
  117. /*
  118.  * Before V6 not all pages had page types, so we do the
  119.  * single meta-data page by hand.
  120.  */
  121. if ((ret =
  122.     __ham_30_hashmeta(dbp, real_name, mbuf)) != 0)
  123. goto err;
  124. if ((ret = __os_seek(dbenv,
  125.     &fh, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0)
  126. goto err;
  127. if ((ret = __os_write(dbenv, &fh, mbuf, 256, &n)) != 0)
  128. goto err;
  129. /*
  130.  * Before V6, we created hash pages one by one as they
  131.  * were needed, using hashhdr.ovfl_point to reserve
  132.  * a block of page numbers for them.  A consequence
  133.  * of this was that, if no overflow pages had been
  134.  * created, the current doubling might extend past
  135.  * the end of the database file.
  136.  *
  137.  * In DB 3.X, we now create all the hash pages
  138.  * belonging to a doubling atomicly;  it's not
  139.  * safe to just save them for later, because when
  140.  * we create an overflow page we'll just create
  141.  * a new last page (whatever that may be).  Grow
  142.  * the database to the end of the current doubling.
  143.  */
  144. if ((ret =
  145.     __ham_30_sizefix(dbp, &fh, real_name, mbuf)) != 0)
  146. goto err;
  147. /* FALLTHROUGH */
  148. case 6:
  149. /*
  150.  * We need the page size to do more.  Rip it out of
  151.  * the meta-data page.
  152.  */
  153. memcpy(&dbp->pgsize, mbuf + 20, sizeof(u_int32_t));
  154. if ((ret = __db_page_pass(
  155.     dbp, real_name, flags, func_31_list, &fh)) != 0)
  156. goto err;
  157. /* FALLTHROUGH */
  158. case 7:
  159. case 8:
  160. break;
  161. default:
  162. __db_err(dbenv, "%s: unsupported hash version: %lu",
  163.     real_name, (u_long)((DBMETA *)mbuf)->version);
  164. ret = DB_OLD_VERSION;
  165. goto err;
  166. }
  167. break;
  168. case DB_QAMMAGIC:
  169. switch (((DBMETA *)mbuf)->version) {
  170. case 1:
  171. /*
  172.  * If we're in a Queue database, the only page that
  173.  * needs upgrading is the meta-database page, don't
  174.  * bother with a full pass.
  175.  */
  176. if ((ret = __qam_31_qammeta(dbp, real_name, mbuf)) != 0)
  177. return (ret);
  178. /* FALLTHROUGH */
  179. case 2:
  180. if ((ret = __qam_32_qammeta(dbp, real_name, mbuf)) != 0)
  181. return (ret);
  182. if ((ret = __os_seek(dbenv,
  183.     &fh, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0)
  184. goto err;
  185. if ((ret = __os_write(dbenv, &fh, mbuf, 256, &n)) != 0)
  186. goto err;
  187. /* FALLTHROUGH */
  188. case 3:
  189. case 4:
  190. break;
  191. default:
  192. __db_err(dbenv, "%s: unsupported queue version: %lu",
  193.     real_name, (u_long)((DBMETA *)mbuf)->version);
  194. ret = DB_OLD_VERSION;
  195. goto err;
  196. }
  197. break;
  198. default:
  199. M_32_SWAP(((DBMETA *)mbuf)->magic);
  200. switch (((DBMETA *)mbuf)->magic) {
  201. case DB_BTREEMAGIC:
  202. case DB_HASHMAGIC:
  203. case DB_QAMMAGIC:
  204. __db_err(dbenv,
  205. "%s: DB->upgrade only supported on native byte-order systems",
  206.     real_name);
  207. break;
  208. default:
  209. __db_err(dbenv,
  210.     "%s: unrecognized file type", real_name);
  211. break;
  212. }
  213. ret = EINVAL;
  214. goto err;
  215. }
  216. ret = __os_fsync(dbenv, &fh);
  217. err: if ((t_ret = __os_closehandle(dbenv, &fh)) != 0 && ret == 0)
  218. ret = t_ret;
  219. __os_free(dbenv, real_name);
  220. /* We're done. */
  221. if (dbp->db_feedback != NULL)
  222. dbp->db_feedback(dbp, DB_UPGRADE, 100);
  223. return (ret);
  224. }
  225. /*
  226.  * __db_page_pass --
  227.  * Walk the pages of the database, upgrading whatever needs it.
  228.  */
  229. static int
  230. __db_page_pass(dbp, real_name, flags, fl, fhp)
  231. DB *dbp;
  232. char *real_name;
  233. u_int32_t flags;
  234. int (* const fl[P_PAGETYPE_MAX])
  235.     __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *));
  236. DB_FH *fhp;
  237. {
  238. DB_ENV *dbenv;
  239. PAGE *page;
  240. db_pgno_t i, pgno_last;
  241. size_t n;
  242. int dirty, ret;
  243. dbenv = dbp->dbenv;
  244. /* Determine the last page of the file. */
  245. if ((ret = __db_lastpgno(dbp, real_name, fhp, &pgno_last)) != 0)
  246. return (ret);
  247. /* Allocate memory for a single page. */
  248. if ((ret = __os_malloc(dbenv, dbp->pgsize, &page)) != 0)
  249. return (ret);
  250. /* Walk the file, calling the underlying conversion functions. */
  251. for (i = 0; i < pgno_last; ++i) {
  252. if (dbp->db_feedback != NULL)
  253. dbp->db_feedback(dbp, DB_UPGRADE, (i * 100)/pgno_last);
  254. if ((ret = __os_seek(dbenv,
  255.     fhp, dbp->pgsize, i, 0, 0, DB_OS_SEEK_SET)) != 0)
  256. break;
  257. if ((ret = __os_read(dbenv, fhp, page, dbp->pgsize, &n)) != 0)
  258. break;
  259. dirty = 0;
  260. if (fl[TYPE(page)] != NULL && (ret = fl[TYPE(page)]
  261.     (dbp, real_name, flags, fhp, page, &dirty)) != 0)
  262. break;
  263. if (dirty) {
  264. if ((ret = __os_seek(dbenv,
  265.     fhp, dbp->pgsize, i, 0, 0, DB_OS_SEEK_SET)) != 0)
  266. break;
  267. if ((ret = __os_write(dbenv,
  268.     fhp, page, dbp->pgsize, &n)) != 0)
  269. break;
  270. }
  271. }
  272. __os_free(dbp->dbenv, page);
  273. return (ret);
  274. }
  275. /*
  276.  * __db_lastpgno --
  277.  * Return the current last page number of the file.
  278.  *
  279.  * PUBLIC: int __db_lastpgno __P((DB *, char *, DB_FH *, db_pgno_t *));
  280.  */
  281. int
  282. __db_lastpgno(dbp, real_name, fhp, pgno_lastp)
  283. DB *dbp;
  284. char *real_name;
  285. DB_FH *fhp;
  286. db_pgno_t *pgno_lastp;
  287. {
  288. DB_ENV *dbenv;
  289. db_pgno_t pgno_last;
  290. u_int32_t mbytes, bytes;
  291. int ret;
  292. dbenv = dbp->dbenv;
  293. if ((ret = __os_ioinfo(dbenv,
  294.     real_name, fhp, &mbytes, &bytes, NULL)) != 0) {
  295. __db_err(dbenv, "%s: %s", real_name, db_strerror(ret));
  296. return (ret);
  297. }
  298. /* Page sizes have to be a power-of-two. */
  299. if (bytes % dbp->pgsize != 0) {
  300. __db_err(dbenv,
  301.     "%s: file size not a multiple of the pagesize", real_name);
  302. return (EINVAL);
  303. }
  304. pgno_last = mbytes * (MEGABYTE / dbp->pgsize);
  305. pgno_last += bytes / dbp->pgsize;
  306. *pgno_lastp = pgno_last;
  307. return (0);
  308. }