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