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