1 /*-
2  * Copyright (c) 2000, 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/db_am.h"
14 #include "dbinc/lock.h"
15 #include "dbinc/txn.h"
16 
17 static int __cdsgroup_abort __P((DB_TXN *txn));
18 static int __cdsgroup_commit __P((DB_TXN *txn, u_int32_t flags));
19 static int __cdsgroup_discard __P((DB_TXN *txn, u_int32_t flags));
20 static u_int32_t __cdsgroup_id __P((DB_TXN *txn));
21 static int __cdsgroup_notsup __P((ENV *env, const char *meth));
22 static int __cdsgroup_prepare __P((DB_TXN *txn, u_int8_t *gid));
23 static int __cdsgroup_get_name __P((DB_TXN *txn, const char **namep));
24 static int __cdsgroup_set_name __P((DB_TXN *txn, const char *name));
25 static int __cdsgroup_set_timeout
26     __P((DB_TXN *txn, db_timeout_t timeout, u_int32_t flags));
27 
28 /*
29  * __cdsgroup_notsup --
30  *	Error when CDS groups don't support a method.
31  */
32 static int
__cdsgroup_notsup(env,meth)33 __cdsgroup_notsup(env, meth)
34 	ENV *env;
35 	const char *meth;
36 {
37 	__db_errx(env, DB_STR_A("0687", "CDS groups do not support %s", "%s"),
38 	    meth);
39 	return (DB_OPNOTSUP);
40 }
41 
42 static int
__cdsgroup_abort(txn)43 __cdsgroup_abort(txn)
44 	DB_TXN *txn;
45 {
46 	ENV *env;
47 
48 	env = txn->mgrp->env;
49 	/*
50 	 * As the txn handle can not be used any more, we call
51 	 * __cdsgroup_commit to release the lock and destroy the handle.
52 	 */
53 	(void)__cdsgroup_commit(txn, 0);
54 	return (__cdsgroup_notsup(env, "abort"));
55 }
56 
57 static int
__cdsgroup_commit(txn,flags)58 __cdsgroup_commit(txn, flags)
59 	DB_TXN *txn;
60 	u_int32_t flags;
61 {
62 	DB_LOCKER *locker;
63 	DB_LOCKREQ lreq;
64 	ENV *env;
65 	int ret, t_ret;
66 
67 	COMPQUIET(flags, 0);
68 	env = txn->mgrp->env;
69 
70 	/* Check for live cursors. */
71 	if (txn->cursors != 0) {
72 		__db_errx(env, DB_STR("0688", "CDS group has active cursors"));
73 		return (EINVAL);
74 	}
75 
76 	/* We may be holding handle locks; release them. */
77 	lreq.op = DB_LOCK_PUT_ALL;
78 	lreq.obj = NULL;
79 	ret = __lock_vec(env, txn->locker, 0, &lreq, 1, NULL);
80 
81 	env = txn->mgrp->env;
82 	locker = txn->locker;
83 	__os_free(env, txn->mgrp);
84 	__os_free(env, txn);
85 	if ((t_ret = __lock_id_free(env, locker)) != 0 && ret == 0)
86 		ret = t_ret;
87 	return (ret);
88 }
89 
__cdsgroup_discard(txn,flags)90 static int __cdsgroup_discard(txn, flags)
91 	DB_TXN *txn;
92 	u_int32_t flags;
93 {
94 	ENV *env;
95 
96 	COMPQUIET(flags, 0);
97 	env = txn->mgrp->env;
98 	/*
99 	 * As the txn handle can not be used any more, we call
100 	 * __cdsgroup_commit to release the lock and destroy the handle.
101 	 */
102 	(void)__cdsgroup_commit(txn, 0);
103 	return (__cdsgroup_notsup(env, "discard"));
104 }
105 
__cdsgroup_id(txn)106 static u_int32_t __cdsgroup_id(txn)
107 	DB_TXN *txn;
108 {
109 	return (txn->txnid);
110 }
111 
__cdsgroup_prepare(txn,gid)112 static int __cdsgroup_prepare(txn, gid)
113 	DB_TXN *txn;
114 	u_int8_t *gid;
115 {
116 	COMPQUIET(gid, NULL);
117 	return (__cdsgroup_notsup(txn->mgrp->env, "prepare"));
118 }
119 
__cdsgroup_get_name(txn,namep)120 static int __cdsgroup_get_name(txn, namep)
121 	DB_TXN *txn;
122 	const char **namep;
123 {
124 	COMPQUIET(namep, NULL);
125 	return (__cdsgroup_notsup(txn->mgrp->env, "get_name"));
126 }
127 
__cdsgroup_set_name(txn,name)128 static int __cdsgroup_set_name(txn, name)
129 	DB_TXN *txn;
130 	const char *name;
131 {
132 	COMPQUIET(name, NULL);
133 	return (__cdsgroup_notsup(txn->mgrp->env, "set_name"));
134 }
135 
__cdsgroup_set_timeout(txn,timeout,flags)136 static int __cdsgroup_set_timeout(txn, timeout, flags)
137 	DB_TXN *txn;
138 	db_timeout_t timeout;
139 	u_int32_t flags;
140 {
141 	COMPQUIET(timeout, 0);
142 	COMPQUIET(flags, 0);
143 	return (__cdsgroup_notsup(txn->mgrp->env, "set_timeout"));
144 }
145 
146 /*
147  * PUBLIC: int __cdsgroup_begin __P((ENV *, DB_TXN **));
148  */
149 int
__cdsgroup_begin(env,txnpp)150 __cdsgroup_begin(env, txnpp)
151 	ENV *env;
152 	DB_TXN **txnpp;
153 {
154 	DB_TXN *txn;
155 	int ret;
156 
157 	*txnpp = txn = NULL;
158 	if ((ret = __os_calloc(env, 1, sizeof(DB_TXN), &txn)) != 0)
159 		goto err;
160 	/*
161 	 * We need a dummy DB_TXNMGR -- it's the only way to get from a
162 	 * transaction handle to the environment handle.
163 	 */
164 	if ((ret = __os_calloc(env, 1, sizeof(DB_TXNMGR), &txn->mgrp)) != 0)
165 		goto err;
166 	txn->mgrp->env = env;
167 
168 	if ((ret = __lock_id(env, &txn->txnid, &txn->locker)) != 0)
169 		goto err;
170 
171 	txn->flags = TXN_FAMILY;
172 	txn->abort = __cdsgroup_abort;
173 	txn->commit = __cdsgroup_commit;
174 	txn->discard = __cdsgroup_discard;
175 	txn->id = __cdsgroup_id;
176 	txn->prepare = __cdsgroup_prepare;
177 	txn->get_name = __cdsgroup_get_name;
178 	txn->set_name = __cdsgroup_set_name;
179 	txn->set_timeout = __cdsgroup_set_timeout;
180 
181 	*txnpp = txn;
182 
183 	if (0) {
184 err:		if (txn != NULL) {
185 			if (txn->mgrp != NULL)
186 				__os_free(env, txn->mgrp);
187 			__os_free(env, txn);
188 		}
189 	}
190 	return (ret);
191 }
192 
193 /*
194  * __cds_txn_begin_pp --
195  *	DB_ENV->cdsgroup_begin
196  *
197  * PUBLIC: int __cdsgroup_begin_pp __P((DB_ENV *, DB_TXN **));
198  */
__cdsgroup_begin_pp(dbenv,txnpp)199 int __cdsgroup_begin_pp(dbenv, txnpp)
200 	DB_ENV *dbenv;
201 	DB_TXN **txnpp;
202 {
203 	DB_THREAD_INFO *ip;
204 	ENV *env;
205 	int ret;
206 
207 	env = dbenv->env;
208 
209 	ENV_ILLEGAL_BEFORE_OPEN(env, "cdsgroup_begin");
210 	if (!CDB_LOCKING(env))
211 		return (__env_not_config(env, "cdsgroup_begin", DB_INIT_CDB));
212 
213 	ENV_ENTER(env, ip);
214 	ret = __cdsgroup_begin(env, txnpp);
215 	ENV_LEAVE(env, ip);
216 	return (ret);
217  }
218