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