1 /*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996, 1997, 1998
5 * Sleepycat Software. All rights reserved.
6 */
7
8 #pragma ident "%Z%%M% %I% %E% SMI"
9
10 #include "config.h"
11
12 #ifndef lint
13 static const char sccsid[] = "@(#)bt_curadj.c 10.69 (Sleepycat) 12/2/98";
14 #endif /* not lint */
15
16 #ifndef NO_SYSTEM_INCLUDES
17 #include <sys/types.h>
18
19 #include <stdlib.h>
20 #endif
21
22 #include "db_int.h"
23 #include "db_page.h"
24 #include "btree.h"
25
26 #ifdef DEBUG
27 /*
28 * __bam_cprint --
29 * Display the current cursor list.
30 *
31 * PUBLIC: int __bam_cprint __P((DB *));
32 */
33 int
__bam_cprint(dbp)34 __bam_cprint(dbp)
35 DB *dbp;
36 {
37 CURSOR *cp;
38 DBC *dbc;
39
40 DB_THREAD_LOCK(dbp);
41 for (dbc = TAILQ_FIRST(&dbp->active_queue);
42 dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
43 cp = (CURSOR *)dbc->internal;
44 fprintf(stderr,
45 "%#0x->%#0x: page: %lu index: %lu dpage %lu dindex: %lu recno: %lu",
46 (u_int)dbc, (u_int)cp, (u_long)cp->pgno, (u_long)cp->indx,
47 (u_long)cp->dpgno, (u_long)cp->dindx, (u_long)cp->recno);
48 if (F_ISSET(cp, C_DELETED))
49 fprintf(stderr, " (deleted)");
50 fprintf(stderr, "\n");
51 }
52 DB_THREAD_UNLOCK(dbp);
53
54 return (0);
55 }
56 #endif /* DEBUG */
57
58 /*
59 * __bam_ca_delete --
60 * Update the cursors when items are deleted and when already deleted
61 * items are overwritten. Return the number of relevant cursors found.
62 *
63 * PUBLIC: int __bam_ca_delete __P((DB *, db_pgno_t, u_int32_t, int));
64 */
65 int
__bam_ca_delete(dbp,pgno,indx,delete)66 __bam_ca_delete(dbp, pgno, indx, delete)
67 DB *dbp;
68 db_pgno_t pgno;
69 u_int32_t indx;
70 int delete;
71 {
72 DBC *dbc;
73 CURSOR *cp;
74 int count; /* !!!: Has to contain max number of cursors. */
75
76 /* Recno is responsible for its own adjustments. */
77 if (dbp->type == DB_RECNO)
78 return (0);
79
80 /*
81 * Adjust the cursors. We don't have to review the cursors for any
82 * thread of control other than the current one, because we have the
83 * page write locked at this point, and any other thread of control
84 * had better be using a different locker ID, meaning only cursors in
85 * our thread of control can be on the page.
86 *
87 * It's possible for multiple cursors within the thread to have write
88 * locks on the same page, but, cursors within a thread must be single
89 * threaded, so all we're locking here is the cursor linked list.
90 */
91 DB_THREAD_LOCK(dbp);
92 for (count = 0, dbc = TAILQ_FIRST(&dbp->active_queue);
93 dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
94 cp = (CURSOR *)dbc->internal;
95
96 if ((cp->pgno == pgno && cp->indx == indx) ||
97 (cp->dpgno == pgno && cp->dindx == indx)) {
98 if (delete)
99 F_SET(cp, C_DELETED);
100 else
101 F_CLR(cp, C_DELETED);
102 ++count;
103 }
104 }
105 DB_THREAD_UNLOCK(dbp);
106
107 return (count);
108 }
109
110 /*
111 * __bam_ca_di --
112 * Adjust the cursors during a delete or insert.
113 *
114 * PUBLIC: void __bam_ca_di __P((DB *, db_pgno_t, u_int32_t, int));
115 */
116 void
__bam_ca_di(dbp,pgno,indx,adjust)117 __bam_ca_di(dbp, pgno, indx, adjust)
118 DB *dbp;
119 db_pgno_t pgno;
120 u_int32_t indx;
121 int adjust;
122 {
123 CURSOR *cp;
124 DBC *dbc;
125
126 /* Recno is responsible for its own adjustments. */
127 if (dbp->type == DB_RECNO)
128 return;
129
130 /*
131 * Adjust the cursors. See the comment in __bam_ca_delete().
132 */
133 DB_THREAD_LOCK(dbp);
134 for (dbc = TAILQ_FIRST(&dbp->active_queue);
135 dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
136 cp = (CURSOR *)dbc->internal;
137 if (cp->pgno == pgno && cp->indx >= indx)
138 cp->indx += adjust;
139 if (cp->dpgno == pgno && cp->dindx >= indx)
140 cp->dindx += adjust;
141 }
142 DB_THREAD_UNLOCK(dbp);
143 }
144
145 /*
146 * __bam_ca_dup --
147 * Adjust the cursors when moving items from a leaf page to a duplicates
148 * page.
149 *
150 * PUBLIC: void __bam_ca_dup __P((DB *,
151 * PUBLIC: db_pgno_t, u_int32_t, u_int32_t, db_pgno_t, u_int32_t));
152 */
153 void
__bam_ca_dup(dbp,fpgno,first,fi,tpgno,ti)154 __bam_ca_dup(dbp, fpgno, first, fi, tpgno, ti)
155 DB *dbp;
156 db_pgno_t fpgno, tpgno;
157 u_int32_t first, fi, ti;
158 {
159 CURSOR *cp;
160 DBC *dbc;
161
162 /* Recno is responsible for its own adjustments. */
163 if (dbp->type == DB_RECNO)
164 return;
165
166 /*
167 * Adjust the cursors. See the comment in __bam_ca_delete().
168 */
169 DB_THREAD_LOCK(dbp);
170 for (dbc = TAILQ_FIRST(&dbp->active_queue);
171 dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
172 cp = (CURSOR *)dbc->internal;
173 /*
174 * Ignore matching entries that have already been moved,
175 * we move from the same location on the leaf page more
176 * than once.
177 */
178 if (cp->dpgno == PGNO_INVALID &&
179 cp->pgno == fpgno && cp->indx == fi) {
180 cp->indx = first;
181 cp->dpgno = tpgno;
182 cp->dindx = ti;
183 }
184 }
185 DB_THREAD_UNLOCK(dbp);
186 }
187
188 /*
189 * __bam_ca_rsplit --
190 * Adjust the cursors when doing reverse splits.
191 *
192 * PUBLIC: void __bam_ca_rsplit __P((DB *, db_pgno_t, db_pgno_t));
193 */
194 void
__bam_ca_rsplit(dbp,fpgno,tpgno)195 __bam_ca_rsplit(dbp, fpgno, tpgno)
196 DB *dbp;
197 db_pgno_t fpgno, tpgno;
198 {
199 CURSOR *cp;
200 DBC *dbc;
201
202 /* Recno is responsible for its own adjustments. */
203 if (dbp->type == DB_RECNO)
204 return;
205
206 /*
207 * Adjust the cursors. See the comment in __bam_ca_delete().
208 */
209 DB_THREAD_LOCK(dbp);
210 for (dbc = TAILQ_FIRST(&dbp->active_queue);
211 dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
212 cp = (CURSOR *)dbc->internal;
213 if (cp->pgno == fpgno)
214 cp->pgno = tpgno;
215 }
216 DB_THREAD_UNLOCK(dbp);
217 }
218
219 /*
220 * __bam_ca_split --
221 * Adjust the cursors when splitting a page.
222 *
223 * PUBLIC: void __bam_ca_split __P((DB *,
224 * PUBLIC: db_pgno_t, db_pgno_t, db_pgno_t, u_int32_t, int));
225 */
226 void
__bam_ca_split(dbp,ppgno,lpgno,rpgno,split_indx,cleft)227 __bam_ca_split(dbp, ppgno, lpgno, rpgno, split_indx, cleft)
228 DB *dbp;
229 db_pgno_t ppgno, lpgno, rpgno;
230 u_int32_t split_indx;
231 int cleft;
232 {
233 DBC *dbc;
234 CURSOR *cp;
235
236 /* Recno is responsible for its own adjustments. */
237 if (dbp->type == DB_RECNO)
238 return;
239
240 /*
241 * Adjust the cursors. See the comment in __bam_ca_delete().
242 *
243 * If splitting the page that a cursor was on, the cursor has to be
244 * adjusted to point to the same record as before the split. Most
245 * of the time we don't adjust pointers to the left page, because
246 * we're going to copy its contents back over the original page. If
247 * the cursor is on the right page, it is decremented by the number of
248 * records split to the left page.
249 */
250 DB_THREAD_LOCK(dbp);
251 for (dbc = TAILQ_FIRST(&dbp->active_queue);
252 dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
253 cp = (CURSOR *)dbc->internal;
254 if (cp->pgno == ppgno)
255 if (cp->indx < split_indx) {
256 if (cleft)
257 cp->pgno = lpgno;
258 } else {
259 cp->pgno = rpgno;
260 cp->indx -= split_indx;
261 }
262 if (cp->dpgno == ppgno)
263 if (cp->dindx < split_indx) {
264 if (cleft)
265 cp->dpgno = lpgno;
266 } else {
267 cp->dpgno = rpgno;
268 cp->dindx -= split_indx;
269 }
270 }
271 DB_THREAD_UNLOCK(dbp);
272 }
273