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