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 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 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 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 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 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 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