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