1 /*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved.
5 *
6 * $Id$
7 */
8
9 #include "db_config.h"
10
11 #include "db_int.h"
12 #include "dbinc/db_page.h"
13 #include "dbinc/heap.h"
14 #include "dbinc/lock.h"
15 #include "dbinc/mp.h"
16
17 /*
18 * __heap_truncate --
19 * Truncate a database.
20 *
21 * PUBLIC: int __heap_truncate __P((DBC *, u_int32_t *));
22 */
23 int
__heap_truncate(dbc,countp)24 __heap_truncate(dbc, countp)
25 DBC *dbc;
26 u_int32_t *countp;
27 {
28 DB *dbp;
29 DB_LOCK lock, meta_lock;
30 DB_MPOOLFILE *mpf;
31 DBT log_dbt;
32 HEAPHDR *hdr;
33 HEAPMETA *meta;
34 HEAPPG *pg;
35 db_pgno_t pgno;
36 int i, ret, t_ret;
37 u_int32_t count, next_region, region_size;
38
39 LOCK_INIT(lock);
40 dbp = dbc->dbp;
41 mpf = dbp->mpf;
42 count = 0;
43 next_region = FIRST_HEAP_RPAGE;
44 region_size = HEAP_REGION_SIZE(dbp);
45
46 /* Traverse the entire database, starting with the metadata pg. */
47 pgno = PGNO_BASE_MD;
48 if ((ret = __db_lget(dbc,
49 LCK_ALWAYS, pgno, DB_LOCK_WRITE, 0, &meta_lock)) != 0)
50 return (ret);
51 if ((ret = __memp_fget(mpf, &pgno,
52 dbc->thread_info, dbc->txn, DB_MPOOL_DIRTY, &meta)) != 0) {
53 __TLPUT(dbc, lock);
54 goto err;
55 }
56
57 for (;;) {
58 pgno++;
59 if ((ret = __db_lget(dbc,
60 LCK_COUPLE, pgno, DB_LOCK_WRITE, 0, &lock)) != 0)
61 break;
62 if ((ret = __memp_fget(mpf, &pgno,
63 dbc->thread_info, dbc->txn, DB_MPOOL_DIRTY, &pg)) != 0) {
64 if (ret == DB_PAGE_NOTFOUND)
65 ret = 0;
66 break;
67 }
68 if (DBC_LOGGING(dbc)) {
69 memset(&log_dbt, 0, sizeof(DBT));
70 log_dbt.data = pg;
71 log_dbt.size = dbp->pgsize;
72 if ((ret = __heap_trunc_page_log(dbp, dbc->txn,
73 &LSN(pg), 0, pgno,
74 &log_dbt, (pgno == next_region), &LSN(pg))) != 0)
75 goto err;
76 } else
77 LSN_NOT_LOGGED(LSN(pg));
78
79 if (pgno == next_region) {
80 DB_ASSERT(dbp->env, TYPE(pg) == P_IHEAP);
81 next_region += region_size + 1;
82 } else {
83 /*
84 * We can't use pg->entries to calculate the record
85 * count, because it can include split records. So we
86 * check the header for each entry and only count
87 * non-split records and the first piece of split
88 * records. But if the page is empty, there's no work to
89 * do.
90 */
91 if (NUM_ENT(pg) != 0)
92 for (i = 0; i <= HEAP_HIGHINDX(pg); i++) {
93 if (HEAP_OFFSETTBL(dbp, pg)[i] == 0)
94 continue;
95 hdr = (HEAPHDR *)P_ENTRY(dbp, pg, i);
96 if (!F_ISSET(hdr, HEAP_RECSPLIT) ||
97 F_ISSET(hdr, HEAP_RECFIRST))
98 count++;
99 }
100 }
101 if ((ret = __memp_fput(mpf,
102 dbc->thread_info, pg, dbc->priority)) != 0)
103 break;
104 if ((ret = __memp_fget(mpf, &pgno,
105 dbc->thread_info, dbc->txn, DB_MPOOL_FREE, &pg)) != 0)
106 break;
107 }
108 if ((t_ret = __TLPUT(dbc, lock)) != 0 && ret == 0)
109 ret = t_ret;
110
111 if (countp != NULL && ret == 0)
112 *countp = count;
113
114 if (DBC_LOGGING(dbc)) {
115 if ((ret = __heap_trunc_meta_log(dbp, dbc->txn, &LSN(meta), 0,
116 meta->dbmeta.pgno, meta->dbmeta.last_pgno,
117 meta->dbmeta.key_count, meta->dbmeta.record_count,
118 meta->curregion, meta->nregions, &LSN(meta))) != 0)
119 goto err;
120 } else
121 LSN_NOT_LOGGED(LSN(meta));
122 meta->dbmeta.key_count = 0;
123 meta->dbmeta.record_count = 0;
124 meta->dbmeta.last_pgno = PGNO_BASE_MD + 1;
125 meta->curregion = 1;
126 meta->nregions = 1;
127
128 if ((ret = __memp_ftruncate(mpf, dbc->txn,
129 dbc->thread_info, PGNO_BASE_MD + 1, MP_TRUNC_NOCACHE)) != 0)
130 goto err;
131
132 /* Create the first region. */
133 pgno = PGNO_BASE_MD + 1;
134 if ((ret = __memp_fget(mpf, &pgno, dbc->thread_info,
135 dbc->txn, DB_MPOOL_CREATE | DB_MPOOL_DIRTY, &pg)) != 0)
136 goto err;
137
138 memset(pg, 0, dbp->pgsize);
139 P_INIT(pg,
140 dbp->pgsize, 1, PGNO_INVALID, PGNO_INVALID, 0, P_IHEAP);
141 ret = __db_log_page(dbp, dbc->txn, &pg->lsn, pgno, (PAGE *)pg);
142 if ((t_ret = __memp_fput(
143 mpf, dbc->thread_info, pg, dbp->priority)) != 0 && ret == 0)
144 ret = t_ret;
145
146 err: if ((t_ret = __memp_fput(mpf,
147 dbc->thread_info, meta, dbc->priority)) != 0 && ret == 0)
148 ret = t_ret;
149 if ((t_ret = __TLPUT(dbc, meta_lock)) && ret == 0)
150 ret = t_ret;
151 return (ret);
152 }
153