1 /*-
2 * Copyright (c) 1996, 2020 Oracle and/or its affiliates. All rights reserved.
3 *
4 * See the file LICENSE for license information.
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/fop.h"
14 #include "dbinc/hash.h"
15 #include "dbinc/mp.h"
16 #include "dbinc/txn.h"
17
18 /*
19 * __crdel_metasub_recover --
20 * Recovery function for metasub.
21 *
22 * PUBLIC: int __crdel_metasub_recover
23 * PUBLIC: __P((ENV *, DBT *, DB_LSN *, db_recops, void *));
24 */
25 int
__crdel_metasub_recover(env,dbtp,lsnp,op,info)26 __crdel_metasub_recover(env, dbtp, lsnp, op, info)
27 ENV *env;
28 DBT *dbtp;
29 DB_LSN *lsnp;
30 db_recops op;
31 void *info;
32 {
33 __crdel_metasub_args *argp;
34 DB *file_dbp;
35 DBC *dbc;
36 DB_MPOOLFILE *mpf;
37 DB_THREAD_INFO *ip;
38 DB_TXN *txn;
39 DB_TXNHEAD *txnhead;
40 PAGE *pagep;
41 int cmp_p, ret, t_ret;
42
43 txnhead = info;
44 ip = txnhead->thread_info;
45 txn = txnhead->txn;
46 pagep = NULL;
47 REC_PRINT(__crdel_metasub_print);
48 REC_INTRO(__crdel_metasub_read, txnhead, 0);
49
50 /*
51 * If we are undoing this operation, but the DB that we got back
52 * was never really opened, then this open was an in-memory open
53 * that did not finish. We can let the file creation take care
54 * of any necessary undo/cleanup.
55 */
56 if (DB_UNDO(op) && !F_ISSET(file_dbp, DB_AM_OPEN_CALLED))
57 goto done;
58
59 if ((ret = __memp_fget(mpf, &argp->pgno, ip, txn, 0, &pagep)) != 0) {
60 /*
61 * If this is an in-memory file, this might be OK. Also, heap
62 * can get there through a truncate and we have to redo page 1
63 */
64 if ((file_dbp->type == DB_HEAP ||
65 F_ISSET(file_dbp, DB_AM_INMEM)) &&
66 (ret = __memp_fget(mpf, &argp->pgno, ip, txn,
67 DB_MPOOL_CREATE | DB_MPOOL_DIRTY, &pagep)) == 0) {
68 if (F_ISSET(file_dbp, DB_AM_INMEM))
69 LSN_NOT_LOGGED(LSN(pagep));
70 } else {
71 *lsnp = argp->prev_lsn;
72 ret = 0;
73 goto out;
74 }
75 }
76
77 cmp_p = LOG_COMPARE(&LSN(pagep), &argp->lsn);
78 CHECK_LSN(env, op, cmp_p, &LSN(pagep), &argp->lsn);
79
80 if (cmp_p == 0 && DB_REDO(op)) {
81 REC_DIRTY(mpf, txnhead, file_dbp->priority, &pagep);
82 memcpy(pagep, argp->page.data, argp->page.size);
83 LSN(pagep) = *lsnp;
84
85 /*
86 * If this was an in-memory database and we are re-creating
87 * and this is the meta-data page, then we need to set up a
88 * bunch of fields in the dbp as well.
89 */
90 if (F_ISSET(file_dbp, DB_AM_INMEM) &&
91 argp->pgno == PGNO_BASE_MD &&
92 (ret = __db_meta_setup(file_dbp->env, file_dbp,
93 file_dbp->dname, (DBMETA *)pagep, 0, DB_CHK_META)) != 0)
94 goto out;
95 } else if (DB_UNDO(op)) {
96 /*
97 * We want to undo this page creation. The page creation
98 * happened in two parts. First, we called __db_pg_alloc which
99 * was logged separately. Then we wrote the meta-data onto
100 * the page. So long as we restore the LSN, then the recovery
101 * for __db_pg_alloc will do everything else.
102 *
103 * Don't bother checking the lsn on the page. If we are
104 * rolling back the next thing is that this page will get
105 * freed. Opening the subdb will have reinitialized the
106 * page, but not the lsn.
107 */
108 REC_DIRTY(mpf, txnhead, file_dbp->priority, &pagep);
109 LSN(pagep) = argp->lsn;
110 }
111
112 done: *lsnp = argp->prev_lsn;
113 ret = 0;
114
115 out: if (pagep != NULL && (t_ret = __memp_fput(mpf,
116 ip, pagep, file_dbp->priority)) != 0 &&
117 ret == 0)
118 ret = t_ret;
119
120 REC_CLOSE;
121 }
122
123 /*
124 * __crdel_inmem_create_recover --
125 * Recovery function for inmem_create.
126 *
127 * PUBLIC: int __crdel_inmem_create_recover
128 * PUBLIC: __P((ENV *, DBT *, DB_LSN *, db_recops, void *));
129 */
130 int
__crdel_inmem_create_recover(env,dbtp,lsnp,op,info)131 __crdel_inmem_create_recover(env, dbtp, lsnp, op, info)
132 ENV *env;
133 DBT *dbtp;
134 DB_LSN *lsnp;
135 db_recops op;
136 void *info;
137 {
138 __crdel_inmem_create_args *argp;
139 DB *dbp;
140 DB_TXNHEAD *txnhead;
141 int do_close, ret, t_ret;
142
143 txnhead = info;
144 dbp = NULL;
145 do_close = 0;
146 REC_PRINT(__crdel_inmem_create_print);
147 REC_NOOP_INTRO(__crdel_inmem_create_read);
148
149 /* First, see if the DB handle already exists. */
150 if (argp->fileid == DB_LOGFILEID_INVALID) {
151 if (DB_REDO(op))
152 ret = USR_ERR(env, ENOENT);
153 else
154 ret = 0;
155 } else
156 ret = __dbreg_id_to_db(env, txnhead->txn,
157 &dbp, argp->fileid, 0);
158
159 if (DB_REDO(op)) {
160 /*
161 * If the dbreg failed, that means that we're creating a
162 * tmp file.
163 */
164 if (ret != 0) {
165 if ((ret = __db_create_internal(&dbp, env, 0)) != 0)
166 goto out;
167
168 F_SET(dbp, DB_AM_RECOVER | DB_AM_INMEM);
169 memcpy(dbp->fileid, argp->fid.data, DB_FILE_ID_LEN);
170 if (((ret = __os_strdup(env,
171 argp->name.data, &dbp->dname)) != 0))
172 goto out;
173
174 /*
175 * This DBP is never going to be entered into the
176 * dbentry table, so if we leave it open here,
177 * then we're going to lose it.
178 */
179 do_close = 1;
180 }
181
182 /* Now, set the fileid. */
183 memcpy(dbp->fileid, argp->fid.data, argp->fid.size);
184 if ((ret = __memp_set_fileid(dbp->mpf, dbp->fileid)) != 0)
185 goto out;
186 dbp->preserve_fid = 1;
187 MAKE_INMEM(dbp);
188 if ((ret = __env_setup(dbp,
189 txnhead->txn, NULL, argp->name.data, TXN_INVALID, 0)) != 0)
190 goto out;
191 ret = __env_mpool(dbp, argp->name.data, 0);
192
193 if (ret == ENOENT) {
194 dbp->pgsize = argp->pgsize;
195 if ((ret = __env_mpool(dbp,
196 argp->name.data, DB_CREATE)) != 0)
197 goto out;
198 } else if (ret != 0)
199 goto out;
200 }
201
202 if (DB_UNDO(op)) {
203 if (ret == 0)
204 ret = __memp_nameop(env, argp->fid.data, NULL,
205 (const char *)argp->name.data, NULL, 1);
206
207 if (ret == ENOENT || ret == DB_DELETED)
208 ret = 0;
209 else
210 goto out;
211 }
212
213 *lsnp = argp->prev_lsn;
214
215 out: if (dbp != NULL) {
216 t_ret = 0;
217
218 if (do_close || ret != 0)
219 t_ret = __db_close(dbp, NULL, DB_NOSYNC);
220 if (t_ret != 0 && ret == 0)
221 ret = t_ret;
222 }
223 REC_NOOP_CLOSE;
224 }
225
226 /*
227 * __crdel_inmem_rename_recover --
228 * Recovery function for inmem_rename.
229 *
230 * PUBLIC: int __crdel_inmem_rename_recover
231 * PUBLIC: __P((ENV *, DBT *, DB_LSN *, db_recops, void *));
232 */
233 int
__crdel_inmem_rename_recover(env,dbtp,lsnp,op,info)234 __crdel_inmem_rename_recover(env, dbtp, lsnp, op, info)
235 ENV *env;
236 DBT *dbtp;
237 DB_LSN *lsnp;
238 db_recops op;
239 void *info;
240 {
241 __crdel_inmem_rename_args *argp;
242 DB_TXNHEAD *txnhead;
243 u_int8_t *fileid;
244 int ret;
245
246 txnhead = info;
247 REC_PRINT(__crdel_inmem_rename_print);
248 REC_NOOP_INTRO(__crdel_inmem_rename_read);
249 fileid = argp->fid.data;
250
251 /* Void out errors because the files may or may not still exist. */
252 if (DB_REDO(op))
253 (void)__memp_nameop(env, fileid,
254 (const char *)argp->newname.data,
255 (const char *)argp->oldname.data,
256 (const char *)argp->newname.data, 1);
257
258 if (DB_UNDO(op))
259 (void)__memp_nameop(env, fileid,
260 (const char *)argp->oldname.data,
261 (const char *)argp->newname.data,
262 (const char *)argp->oldname.data, 1);
263
264 *lsnp = argp->prev_lsn;
265 ret = 0;
266
267 COMPQUIET(txnhead, NULL);
268 REC_NOOP_CLOSE;
269 }
270
271 /*
272 * __crdel_inmem_remove_recover --
273 * Recovery function for inmem_remove.
274 *
275 * PUBLIC: int __crdel_inmem_remove_recover
276 * PUBLIC: __P((ENV *, DBT *, DB_LSN *, db_recops, void *));
277 */
278 int
__crdel_inmem_remove_recover(env,dbtp,lsnp,op,info)279 __crdel_inmem_remove_recover(env, dbtp, lsnp, op, info)
280 ENV *env;
281 DBT *dbtp;
282 DB_LSN *lsnp;
283 db_recops op;
284 void *info;
285 {
286 __crdel_inmem_remove_args *argp;
287 int ret;
288
289 REC_PRINT(__crdel_inmem_remove_print);
290 REC_NOOP_INTRO(__crdel_inmem_remove_read);
291
292 /*
293 * Since removes are delayed; there is no undo for a remove; only redo.
294 * The remove may fail, which is OK.
295 */
296 if (DB_REDO(op)) {
297 (void)__memp_nameop(env,
298 argp->fid.data, NULL, argp->name.data, NULL, 1);
299 }
300
301 *lsnp = argp->prev_lsn;
302 ret = 0;
303
304 COMPQUIET(info, NULL);
305 REC_NOOP_CLOSE;
306 }
307