1 /* $NetBSD: id2entry.c,v 1.3 2021/08/14 16:15:00 christos Exp $ */ 2 3 /* id2entry.c - routines to deal with the id2entry database */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2000-2021 The OpenLDAP Foundation. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted only as authorized by the OpenLDAP 12 * Public License. 13 * 14 * A copy of this license is available in the file LICENSE in the 15 * top-level directory of the distribution or, alternatively, at 16 * <http://www.OpenLDAP.org/license.html>. 17 */ 18 19 #include <sys/cdefs.h> 20 __RCSID("$NetBSD: id2entry.c,v 1.3 2021/08/14 16:15:00 christos Exp $"); 21 22 #include "portable.h" 23 24 #include <stdio.h> 25 #include <ac/string.h> 26 #include <ac/errno.h> 27 28 #include "back-mdb.h" 29 30 typedef struct Ecount { 31 ber_len_t len; /* total entry size */ 32 ber_len_t dlen; /* contiguous data size */ 33 int nattrs; 34 int nvals; 35 int offset; 36 Attribute *multi; 37 } Ecount; 38 39 static int mdb_entry_partsize(struct mdb_info *mdb, MDB_txn *txn, Entry *e, 40 Ecount *eh); 41 static int mdb_entry_encode(Operation *op, Entry *e, MDB_val *data, 42 Ecount *ec); 43 static Entry *mdb_entry_alloc( Operation *op, int nattrs, int nvals ); 44 45 #define ID2VKSZ (sizeof(ID)+2) 46 47 int 48 mdb_id2v_compare( 49 const MDB_val *usrkey, 50 const MDB_val *curkey 51 ) 52 { 53 unsigned short *uv, *cv; 54 ID ui, ci; 55 int rc; 56 57 memcpy(&ui, usrkey->mv_data, sizeof(ID)); 58 memcpy(&ci, curkey->mv_data, sizeof(ID)); 59 if (ui < ci) 60 return -1; 61 if (ui > ci) 62 return 1; 63 uv = usrkey->mv_data; 64 cv = curkey->mv_data; 65 return uv[sizeof(ID)/2] - cv[sizeof(ID)/2]; 66 } 67 68 /* usrkey[0] is the key in DB format, as described at mdb_mval_put. 69 * usrkey[1] is the value we'll actually match against. 70 * usrkey[2] is the attributeDescription for this value. 71 */ 72 int 73 mdb_id2v_dupsort( 74 const MDB_val *usrkey, 75 const MDB_val *curkey 76 ) 77 { 78 AttributeDescription *ad = usrkey[2].mv_data; 79 struct berval bv1, bv2; 80 int rc, match, olen; 81 unsigned short s; 82 char *ptr; 83 84 ptr = curkey->mv_data + curkey->mv_size - 2; 85 memcpy(&s, ptr, 2); 86 bv2.bv_val = curkey->mv_data; 87 bv2.bv_len = curkey->mv_size - 3; 88 if (s) 89 bv2.bv_len -= (s+1); 90 91 bv1.bv_val = usrkey[1].mv_data; 92 bv1.bv_len = usrkey[1].mv_size; 93 94 if (ad) { 95 MatchingRule *mr = ad->ad_type->sat_equality; 96 rc = mr->smr_match(&match, SLAP_MR_EQUALITY 97 | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX 98 | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH 99 | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, 100 ad->ad_type->sat_syntax, mr, &bv1, &bv2); 101 } else { 102 match = ber_bvcmp(&bv1, &bv2); 103 } 104 105 return match; 106 } 107 108 /* Values are stored as 109 * [normalized-value NUL ] original-value NUL 2-byte-len 110 * The trailing 2-byte-len is zero if there is no normalized value. 111 * Otherwise, it is the length of the original-value. 112 */ 113 int mdb_mval_put(Operation *op, MDB_cursor *mc, ID id, Attribute *a) 114 { 115 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; 116 MDB_val key, data[3]; 117 char *buf; 118 char ivk[ID2VKSZ]; 119 unsigned i; 120 unsigned short s; 121 int rc, len; 122 123 memcpy(ivk, &id, sizeof(id)); 124 s = mdb->mi_adxs[a->a_desc->ad_index]; 125 memcpy(ivk+sizeof(ID), &s, 2); 126 key.mv_data = &ivk; 127 key.mv_size = sizeof(ivk); 128 if ((a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED) || a->a_desc == slap_schema.si_ad_objectClass) 129 data[2].mv_data = NULL; 130 else 131 data[2].mv_data = a->a_desc; 132 133 for (i=0; i<a->a_numvals; i++) { 134 len = a->a_nvals[i].bv_len + 1 + 2; 135 if (a->a_nvals != a->a_vals) { 136 len += a->a_vals[i].bv_len + 1; 137 data[1].mv_data = a->a_nvals[i].bv_val; 138 data[1].mv_size = a->a_nvals[i].bv_len; 139 } else { 140 data[1].mv_data = a->a_vals[i].bv_val; 141 data[1].mv_size = a->a_vals[i].bv_len; 142 } 143 data[0].mv_size = len; 144 buf = op->o_tmpalloc( len, op->o_tmpmemctx ); 145 data[0].mv_data = buf; 146 memcpy(buf, a->a_nvals[i].bv_val, a->a_nvals[i].bv_len); 147 buf += a->a_nvals[i].bv_len; 148 *buf++ = 0; 149 if (a->a_nvals != a->a_vals) { 150 s = a->a_vals[i].bv_len; 151 memcpy(buf, a->a_vals[i].bv_val, a->a_vals[i].bv_len); 152 buf += a->a_vals[i].bv_len; 153 *buf++ = 0; 154 memcpy(buf, &s, 2); 155 } else { 156 *buf++ = 0; 157 *buf++ = 0; 158 } 159 rc = mdb_cursor_put(mc, &key, data, 0); 160 op->o_tmpfree( data[0].mv_data, op->o_tmpmemctx ); 161 if (rc) 162 return rc; 163 } 164 return 0; 165 } 166 167 int mdb_mval_del(Operation *op, MDB_cursor *mc, ID id, Attribute *a) 168 { 169 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; 170 MDB_val key, data[3]; 171 char *ptr; 172 char ivk[ID2VKSZ]; 173 unsigned i; 174 int rc; 175 unsigned short s; 176 177 memcpy(ivk, &id, sizeof(id)); 178 s = mdb->mi_adxs[a->a_desc->ad_index]; 179 memcpy(ivk+sizeof(ID), &s, 2); 180 key.mv_data = &ivk; 181 key.mv_size = sizeof(ivk); 182 if ((a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED) || a->a_desc == slap_schema.si_ad_objectClass) 183 data[2].mv_data = NULL; 184 else 185 data[2].mv_data = a->a_desc; 186 187 if (a->a_numvals) { 188 for (i=0; i<a->a_numvals; i++) { 189 data[0].mv_data = a->a_nvals[i].bv_val; 190 data[0].mv_size = a->a_nvals[i].bv_len+1; 191 if (a->a_nvals != a->a_vals) { 192 data[1].mv_data = a->a_nvals[i].bv_val; 193 data[1].mv_size = a->a_nvals[i].bv_len; 194 } else { 195 data[1].mv_data = a->a_vals[i].bv_val; 196 data[1].mv_size = a->a_vals[i].bv_len; 197 } 198 rc = mdb_cursor_get(mc, &key, data, MDB_GET_BOTH_RANGE); 199 if (rc) 200 return rc; 201 rc = mdb_cursor_del(mc, 0); 202 if (rc) 203 return rc; 204 } 205 } else { 206 rc = mdb_cursor_get(mc, &key, data, MDB_SET); 207 if (rc) 208 return rc; 209 rc = mdb_cursor_del(mc, MDB_NODUPDATA); 210 } 211 return rc; 212 } 213 214 static int mdb_mval_get(Operation *op, MDB_cursor *mc, ID id, Attribute *a, int have_nvals) 215 { 216 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; 217 MDB_val key, data[3]; 218 char *ptr; 219 char ivk[ID2VKSZ]; 220 unsigned i; 221 int rc = 0; 222 unsigned short s; 223 224 memcpy(ivk, &id, sizeof(id)); 225 s = mdb->mi_adxs[a->a_desc->ad_index]; 226 memcpy(ivk+sizeof(ID), &s, 2); 227 key.mv_data = &ivk; 228 key.mv_size = sizeof(ivk); 229 230 /* not needed */ 231 if ((a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED) || a->a_desc == slap_schema.si_ad_objectClass) 232 data[2].mv_data = NULL; 233 else 234 data[2].mv_data = a->a_desc; 235 236 if (have_nvals) 237 a->a_nvals = a->a_vals + a->a_numvals + 1; 238 else 239 a->a_nvals = a->a_vals; 240 for (i=0; i<a->a_numvals; i++) { 241 if (!i) 242 rc = mdb_cursor_get(mc, &key, data, MDB_SET); 243 else 244 rc = mdb_cursor_get(mc, &key, data, MDB_NEXT_DUP); 245 if (rc) 246 break; 247 ptr = (char*)data[0].mv_data + data[0].mv_size - 2; 248 memcpy(&s, ptr, 2); 249 if (have_nvals) { 250 a->a_nvals[i].bv_val = data[0].mv_data; 251 a->a_vals[i].bv_len = s; 252 a->a_vals[i].bv_val = ptr - a->a_vals[i].bv_len - 1; 253 a->a_nvals[i].bv_len = a->a_vals[i].bv_val - a->a_nvals[i].bv_val - 1; 254 } else { 255 assert(!s); 256 a->a_vals[i].bv_val = data[0].mv_data; 257 a->a_vals[i].bv_len = data[0].mv_size - 3; 258 } 259 } 260 a->a_numvals = i; 261 BER_BVZERO(&a->a_vals[i]); 262 if (have_nvals) { 263 BER_BVZERO(&a->a_nvals[i]); 264 } 265 return rc; 266 } 267 268 #define ADD_FLAGS (MDB_NOOVERWRITE|MDB_APPEND) 269 270 static int mdb_id2entry_put( 271 Operation *op, 272 MDB_txn *txn, 273 MDB_cursor *mc, 274 Entry *e, 275 int flag ) 276 { 277 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; 278 Ecount ec; 279 MDB_val key, data; 280 int rc, adding = flag, prev_ads = mdb->mi_numads; 281 282 /* We only store rdns, and they go in the dn2id database. */ 283 284 key.mv_data = &e->e_id; 285 key.mv_size = sizeof(ID); 286 287 rc = mdb_entry_partsize( mdb, txn, e, &ec ); 288 if (rc) { 289 rc = LDAP_OTHER; 290 goto fail; 291 } 292 293 flag |= MDB_RESERVE; 294 295 if (e->e_id < mdb->mi_nextid) 296 flag &= ~MDB_APPEND; 297 298 if (mdb->mi_maxentrysize && ec.len > mdb->mi_maxentrysize) { 299 rc = LDAP_ADMINLIMIT_EXCEEDED; 300 goto fail; 301 } 302 303 again: 304 data.mv_size = ec.dlen; 305 if ( mc ) 306 rc = mdb_cursor_put( mc, &key, &data, flag ); 307 else 308 rc = mdb_put( txn, mdb->mi_id2entry, &key, &data, flag ); 309 if (rc == MDB_SUCCESS) { 310 rc = mdb_entry_encode( op, e, &data, &ec ); 311 if( rc != LDAP_SUCCESS ) 312 goto fail; 313 /* Handle adds of large multi-valued attrs here. 314 * Modifies handle them directly. 315 */ 316 if (adding && ec.multi) { 317 MDB_cursor *mvc; 318 Attribute *a; 319 rc = mdb_cursor_open( txn, mdb->mi_dbis[MDB_ID2VAL], &mvc ); 320 if( !rc ) { 321 for ( a = ec.multi; a; a=a->a_next ) { 322 if (!(a->a_flags & SLAP_ATTR_BIG_MULTI)) 323 continue; 324 rc = mdb_mval_put( op, mvc, e->e_id, a ); 325 if( rc ) 326 break; 327 } 328 mdb_cursor_close( mvc ); 329 } 330 if ( rc ) { 331 Debug( LDAP_DEBUG_ANY, 332 "mdb_id2entry_put: mdb_mval_put failed: %s(%d) \"%s\"\n", 333 mdb_strerror(rc), rc, 334 e->e_nname.bv_val ); 335 rc = LDAP_OTHER; 336 goto fail; 337 } 338 } 339 } 340 if (rc) { 341 /* Was there a hole from slapadd? */ 342 if ( (flag & MDB_NOOVERWRITE) && data.mv_size == 0 ) { 343 flag &= ~ADD_FLAGS; 344 goto again; 345 } 346 Debug( LDAP_DEBUG_ANY, 347 "mdb_id2entry_put: mdb_put failed: %s(%d) \"%s\"\n", 348 mdb_strerror(rc), rc, 349 e->e_nname.bv_val ); 350 if ( rc != MDB_KEYEXIST ) 351 rc = LDAP_OTHER; 352 } 353 fail: 354 if (rc) { 355 mdb_ad_unwind( mdb, prev_ads ); 356 } 357 return rc; 358 } 359 360 /* 361 * This routine adds (or updates) an entry on disk. 362 */ 363 int mdb_id2entry_add( 364 Operation *op, 365 MDB_txn *txn, 366 MDB_cursor *mc, 367 Entry *e ) 368 { 369 return mdb_id2entry_put(op, txn, mc, e, ADD_FLAGS); 370 } 371 372 int mdb_id2entry_update( 373 Operation *op, 374 MDB_txn *txn, 375 MDB_cursor *mc, 376 Entry *e ) 377 { 378 return mdb_id2entry_put(op, txn, mc, e, 0); 379 } 380 381 int mdb_id2edata( 382 Operation *op, 383 MDB_cursor *mc, 384 ID id, 385 MDB_val *data ) 386 { 387 MDB_val key; 388 int rc; 389 390 key.mv_data = &id; 391 key.mv_size = sizeof(ID); 392 393 /* fetch it */ 394 rc = mdb_cursor_get( mc, &key, data, MDB_SET ); 395 /* stubs from missing parents - DB is actually invalid */ 396 if ( rc == MDB_SUCCESS && !data->mv_size ) 397 rc = MDB_NOTFOUND; 398 return rc; 399 } 400 401 int mdb_id2entry( 402 Operation *op, 403 MDB_cursor *mc, 404 ID id, 405 Entry **e ) 406 { 407 MDB_val key, data; 408 int rc = 0; 409 410 *e = NULL; 411 412 key.mv_data = &id; 413 key.mv_size = sizeof(ID); 414 415 /* fetch it */ 416 rc = mdb_cursor_get( mc, &key, &data, MDB_SET ); 417 if ( rc == MDB_NOTFOUND ) { 418 /* Looking for root entry on an empty-dn suffix? */ 419 if ( !id && BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] )) { 420 struct berval gluebv = BER_BVC("glue"); 421 Entry *r = mdb_entry_alloc(op, 2, 4); 422 Attribute *a = r->e_attrs; 423 struct berval *bptr; 424 425 r->e_id = 0; 426 r->e_ocflags = SLAP_OC_GLUE|SLAP_OC__END; 427 bptr = a->a_vals; 428 a->a_flags = SLAP_ATTR_DONT_FREE_DATA | SLAP_ATTR_DONT_FREE_VALS; 429 a->a_desc = slap_schema.si_ad_objectClass; 430 a->a_nvals = a->a_vals; 431 a->a_numvals = 1; 432 *bptr++ = gluebv; 433 BER_BVZERO(bptr); 434 bptr++; 435 a->a_next = a+1; 436 a = a->a_next; 437 a->a_flags = SLAP_ATTR_DONT_FREE_DATA | SLAP_ATTR_DONT_FREE_VALS; 438 a->a_desc = slap_schema.si_ad_structuralObjectClass; 439 a->a_vals = bptr; 440 a->a_nvals = a->a_vals; 441 a->a_numvals = 1; 442 *bptr++ = gluebv; 443 BER_BVZERO(bptr); 444 a->a_next = NULL; 445 *e = r; 446 return MDB_SUCCESS; 447 } 448 } 449 /* stubs from missing parents - DB is actually invalid */ 450 if ( rc == MDB_SUCCESS && !data.mv_size ) 451 rc = MDB_NOTFOUND; 452 if ( rc ) return rc; 453 454 rc = mdb_entry_decode( op, mdb_cursor_txn( mc ), &data, id, e ); 455 if ( rc ) return rc; 456 457 (*e)->e_id = id; 458 (*e)->e_name.bv_val = NULL; 459 (*e)->e_nname.bv_val = NULL; 460 461 return rc; 462 } 463 464 int mdb_id2entry_delete( 465 BackendDB *be, 466 MDB_txn *tid, 467 Entry *e ) 468 { 469 struct mdb_info *mdb = (struct mdb_info *) be->be_private; 470 MDB_dbi dbi = mdb->mi_id2entry; 471 MDB_val key; 472 MDB_cursor *mvc; 473 int rc; 474 475 key.mv_data = &e->e_id; 476 key.mv_size = sizeof(ID); 477 478 /* delete from database */ 479 rc = mdb_del( tid, dbi, &key, NULL ); 480 if (rc) 481 return rc; 482 rc = mdb_cursor_open( tid, mdb->mi_dbis[MDB_ID2VAL], &mvc ); 483 if (rc) 484 return rc; 485 486 rc = mdb_cursor_get( mvc, &key, NULL, MDB_SET_RANGE ); 487 if (rc) { 488 if (rc == MDB_NOTFOUND) 489 rc = MDB_SUCCESS; 490 return rc; 491 } 492 while (*(ID *)key.mv_data == e->e_id ) { 493 rc = mdb_cursor_del( mvc, MDB_NODUPDATA ); 494 if (rc) 495 return rc; 496 rc = mdb_cursor_get( mvc, &key, NULL, MDB_GET_CURRENT ); 497 if (rc) { 498 if (rc == MDB_NOTFOUND) 499 rc = MDB_SUCCESS; 500 break; 501 } 502 } 503 return rc; 504 } 505 506 static Entry * mdb_entry_alloc( 507 Operation *op, 508 int nattrs, 509 int nvals ) 510 { 511 Entry *e = op->o_tmpalloc( sizeof(Entry) + 512 nattrs * sizeof(Attribute) + 513 nvals * sizeof(struct berval), op->o_tmpmemctx ); 514 BER_BVZERO(&e->e_bv); 515 e->e_private = e; 516 if (nattrs) { 517 e->e_attrs = (Attribute *)(e+1); 518 e->e_attrs->a_vals = (struct berval *)(e->e_attrs+nattrs); 519 } else { 520 e->e_attrs = NULL; 521 } 522 523 return e; 524 } 525 526 int mdb_entry_return( 527 Operation *op, 528 Entry *e 529 ) 530 { 531 if ( !e ) 532 return 0; 533 if ( e->e_private ) { 534 if ( op->o_hdr && op->o_tmpmfuncs ) { 535 op->o_tmpfree( e->e_nname.bv_val, op->o_tmpmemctx ); 536 op->o_tmpfree( e->e_name.bv_val, op->o_tmpmemctx ); 537 op->o_tmpfree( e, op->o_tmpmemctx ); 538 } else { 539 ch_free( e->e_nname.bv_val ); 540 ch_free( e->e_name.bv_val ); 541 ch_free( e ); 542 } 543 } else { 544 entry_free( e ); 545 } 546 return 0; 547 } 548 549 int mdb_entry_release( 550 Operation *op, 551 Entry *e, 552 int rw ) 553 { 554 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; 555 struct mdb_op_info *moi = NULL; 556 557 /* slapMode : SLAP_SERVER_MODE, SLAP_TOOL_MODE, 558 SLAP_TRUNCATE_MODE, SLAP_UNDEFINED_MODE */ 559 560 int release = 1; 561 if ( slapMode & SLAP_SERVER_MODE ) { 562 OpExtra *oex; 563 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) { 564 release = 0; 565 if ( oex->oe_key == mdb ) { 566 mdb_entry_return( op, e ); 567 moi = (mdb_op_info *)oex; 568 /* If it was setup by entry_get we should probably free it */ 569 if (( moi->moi_flag & (MOI_FREEIT|MOI_KEEPER)) == MOI_FREEIT ) { 570 moi->moi_ref--; 571 if ( moi->moi_ref < 1 ) { 572 mdb_txn_reset( moi->moi_txn ); 573 moi->moi_ref = 0; 574 LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next ); 575 op->o_tmpfree( moi, op->o_tmpmemctx ); 576 } 577 } 578 break; 579 } 580 } 581 } 582 583 if (release) 584 mdb_entry_return( op, e ); 585 586 return 0; 587 } 588 589 /* return LDAP_SUCCESS IFF we can retrieve the specified entry. 590 */ 591 int mdb_entry_get( 592 Operation *op, 593 struct berval *ndn, 594 ObjectClass *oc, 595 AttributeDescription *at, 596 int rw, 597 Entry **ent ) 598 { 599 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; 600 struct mdb_op_info *moi = NULL; 601 MDB_txn *txn = NULL; 602 Entry *e = NULL; 603 int rc; 604 const char *at_name = at ? at->ad_cname.bv_val : "(null)"; 605 606 Debug( LDAP_DEBUG_ARGS, 607 "=> mdb_entry_get: ndn: \"%s\"\n", ndn->bv_val ); 608 Debug( LDAP_DEBUG_ARGS, 609 "=> mdb_entry_get: oc: \"%s\", at: \"%s\"\n", 610 oc ? oc->soc_cname.bv_val : "(null)", at_name ); 611 612 rc = mdb_opinfo_get( op, mdb, rw == 0, &moi ); 613 if ( rc ) 614 return LDAP_OTHER; 615 txn = moi->moi_txn; 616 617 /* can we find entry */ 618 rc = mdb_dn2entry( op, txn, NULL, ndn, &e, NULL, 0 ); 619 switch( rc ) { 620 case MDB_NOTFOUND: 621 case 0: 622 break; 623 default: 624 return (rc != LDAP_BUSY) ? LDAP_OTHER : LDAP_BUSY; 625 } 626 if (e == NULL) { 627 Debug( LDAP_DEBUG_ACL, 628 "=> mdb_entry_get: cannot find entry: \"%s\"\n", 629 ndn->bv_val ); 630 rc = LDAP_NO_SUCH_OBJECT; 631 goto return_results; 632 } 633 634 Debug( LDAP_DEBUG_ACL, 635 "=> mdb_entry_get: found entry: \"%s\"\n", 636 ndn->bv_val ); 637 638 if ( oc && !is_entry_objectclass( e, oc, 0 )) { 639 Debug( LDAP_DEBUG_ACL, 640 "<= mdb_entry_get: failed to find objectClass %s\n", 641 oc->soc_cname.bv_val ); 642 rc = LDAP_NO_SUCH_ATTRIBUTE; 643 goto return_results; 644 } 645 646 /* NOTE: attr_find() or attrs_find()? */ 647 if ( at && attr_find( e->e_attrs, at ) == NULL ) { 648 Debug( LDAP_DEBUG_ACL, 649 "<= mdb_entry_get: failed to find attribute %s\n", 650 at->ad_cname.bv_val ); 651 rc = LDAP_NO_SUCH_ATTRIBUTE; 652 goto return_results; 653 } 654 655 return_results: 656 if( rc != LDAP_SUCCESS ) { 657 /* free entry */ 658 mdb_entry_release( op, e, rw ); 659 } else { 660 *ent = e; 661 } 662 663 Debug( LDAP_DEBUG_TRACE, 664 "mdb_entry_get: rc=%d\n", 665 rc ); 666 return(rc); 667 } 668 669 static void 670 mdb_reader_free( void *key, void *data ) 671 { 672 MDB_txn *txn = data; 673 674 if ( txn ) mdb_txn_abort( txn ); 675 } 676 677 /* free up any keys used by the main thread */ 678 void 679 mdb_reader_flush( MDB_env *env ) 680 { 681 void *data; 682 void *ctx = ldap_pvt_thread_pool_context(); 683 684 if ( !ldap_pvt_thread_pool_getkey( ctx, env, &data, NULL ) ) { 685 ldap_pvt_thread_pool_setkey( ctx, env, NULL, 0, NULL, NULL ); 686 mdb_reader_free( env, data ); 687 } 688 } 689 690 extern MDB_txn *mdb_tool_txn; 691 692 int 693 mdb_opinfo_get( Operation *op, struct mdb_info *mdb, int rdonly, mdb_op_info **moip ) 694 { 695 int rc, renew = 0; 696 void *data; 697 void *ctx; 698 mdb_op_info *moi = NULL; 699 OpExtra *oex; 700 701 assert( op != NULL ); 702 703 if ( !mdb || !moip ) return -1; 704 705 /* If no op was provided, try to find the ctx anyway... */ 706 if ( op ) { 707 ctx = op->o_threadctx; 708 } else { 709 ctx = ldap_pvt_thread_pool_context(); 710 } 711 712 if ( op ) { 713 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) { 714 if ( oex->oe_key == mdb ) break; 715 } 716 moi = (mdb_op_info *)oex; 717 } 718 719 if ( !moi ) { 720 moi = *moip; 721 722 if ( !moi ) { 723 if ( op ) { 724 moi = op->o_tmpalloc(sizeof(struct mdb_op_info),op->o_tmpmemctx); 725 } else { 726 moi = ch_malloc(sizeof(mdb_op_info)); 727 } 728 moi->moi_flag = MOI_FREEIT; 729 *moip = moi; 730 } 731 LDAP_SLIST_INSERT_HEAD( &op->o_extra, &moi->moi_oe, oe_next ); 732 moi->moi_oe.oe_key = mdb; 733 moi->moi_ref = 0; 734 moi->moi_txn = NULL; 735 } 736 737 if ( !rdonly ) { 738 /* This op started as a reader, but now wants to write. */ 739 if ( moi->moi_flag & MOI_READER ) { 740 moi = *moip; 741 LDAP_SLIST_INSERT_HEAD( &op->o_extra, &moi->moi_oe, oe_next ); 742 } else { 743 /* This op is continuing an existing write txn */ 744 *moip = moi; 745 } 746 moi->moi_ref++; 747 if ( !moi->moi_txn ) { 748 if (( slapMode & SLAP_TOOL_MODE ) && mdb_tool_txn ) { 749 moi->moi_txn = mdb_tool_txn; 750 } else { 751 int flag = 0; 752 #ifdef SLAP_CONTROL_X_LAZY_COMMIT 753 if ( get_lazyCommit( op )) 754 flag |= MDB_NOMETASYNC; 755 #endif 756 rc = mdb_txn_begin( mdb->mi_dbenv, NULL, flag, &moi->moi_txn ); 757 if (rc) { 758 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n", 759 mdb_strerror(rc), rc ); 760 } 761 return rc; 762 } 763 } 764 return 0; 765 } 766 767 /* OK, this is a reader */ 768 if ( !moi->moi_txn ) { 769 if (( slapMode & SLAP_TOOL_MODE ) && mdb_tool_txn ) { 770 moi->moi_txn = mdb_tool_txn; 771 goto ok; 772 } 773 if ( !ctx ) { 774 /* Shouldn't happen unless we're single-threaded */ 775 rc = mdb_txn_begin( mdb->mi_dbenv, NULL, MDB_RDONLY, &moi->moi_txn ); 776 if (rc) { 777 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n", 778 mdb_strerror(rc), rc ); 779 } 780 return rc; 781 } 782 if ( ldap_pvt_thread_pool_getkey( ctx, mdb->mi_dbenv, &data, NULL ) ) { 783 rc = mdb_txn_begin( mdb->mi_dbenv, NULL, MDB_RDONLY, &moi->moi_txn ); 784 if (rc) { 785 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n", 786 mdb_strerror(rc), rc ); 787 return rc; 788 } 789 data = moi->moi_txn; 790 if ( ( rc = ldap_pvt_thread_pool_setkey( ctx, mdb->mi_dbenv, 791 data, mdb_reader_free, NULL, NULL ) ) ) { 792 mdb_txn_abort( moi->moi_txn ); 793 moi->moi_txn = NULL; 794 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: thread_pool_setkey failed err (%d)\n", 795 rc ); 796 return rc; 797 } 798 } else { 799 moi->moi_txn = data; 800 renew = 1; 801 } 802 moi->moi_flag |= MOI_READER; 803 } 804 ok: 805 if ( moi->moi_ref < 1 ) { 806 moi->moi_ref = 0; 807 } 808 if ( renew ) { 809 rc = mdb_txn_renew( moi->moi_txn ); 810 assert(!rc); 811 } 812 moi->moi_ref++; 813 if ( *moip != moi ) 814 *moip = moi; 815 816 return 0; 817 } 818 819 int mdb_txn( Operation *op, int txnop, OpExtra **ptr ) 820 { 821 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; 822 mdb_op_info **moip = (mdb_op_info **)ptr, *moi = *moip; 823 int rc; 824 825 switch( txnop ) { 826 case SLAP_TXN_BEGIN: 827 rc = mdb_opinfo_get( op, mdb, 0, moip ); 828 if ( !rc ) { 829 moi = *moip; 830 moi->moi_flag |= MOI_KEEPER; 831 } 832 return rc; 833 case SLAP_TXN_COMMIT: 834 rc = mdb_txn_commit( moi->moi_txn ); 835 if ( rc ) 836 mdb->mi_numads = 0; 837 op->o_tmpfree( moi, op->o_tmpmemctx ); 838 return rc; 839 case SLAP_TXN_ABORT: 840 mdb->mi_numads = 0; 841 mdb_txn_abort( moi->moi_txn ); 842 op->o_tmpfree( moi, op->o_tmpmemctx ); 843 return 0; 844 } 845 return LDAP_OTHER; 846 } 847 848 /* Count up the sizes of the components of an entry */ 849 static int mdb_entry_partsize(struct mdb_info *mdb, MDB_txn *txn, Entry *e, 850 Ecount *eh) 851 { 852 ber_len_t len, dlen; 853 int i, nat = 0, nval = 0, nnval = 0, doff = 0; 854 Attribute *a; 855 unsigned hi; 856 857 eh->multi = NULL; 858 len = 4*sizeof(int); /* nattrs, nvals, ocflags, offset */ 859 dlen = len; 860 for (a=e->e_attrs; a; a=a->a_next) { 861 /* For AttributeDesc, we only store the attr index */ 862 nat++; 863 if (a->a_desc->ad_index >= MDB_MAXADS) { 864 Debug( LDAP_DEBUG_ANY, "mdb_entry_partsize: too many AttributeDescriptions used\n" ); 865 return LDAP_OTHER; 866 } 867 if (!mdb->mi_adxs[a->a_desc->ad_index]) { 868 int rc = mdb_ad_get(mdb, txn, a->a_desc); 869 if (rc) 870 return rc; 871 } 872 len += 2*sizeof(int); /* AD index, numvals */ 873 dlen += 2*sizeof(int); 874 nval += a->a_numvals + 1; /* empty berval at end */ 875 mdb_attr_multi_thresh( mdb, a->a_desc, &hi, NULL ); 876 if (a->a_numvals > hi) 877 a->a_flags |= SLAP_ATTR_BIG_MULTI; 878 if (a->a_flags & SLAP_ATTR_BIG_MULTI) 879 doff += a->a_numvals; 880 for (i=0; i<a->a_numvals; i++) { 881 int alen = a->a_vals[i].bv_len + 1 + sizeof(int); /* len */ 882 len += alen; 883 if (a->a_flags & SLAP_ATTR_BIG_MULTI) { 884 if (!eh->multi) 885 eh->multi = a; 886 } else { 887 dlen += alen; 888 } 889 } 890 if (a->a_nvals != a->a_vals) { 891 nval += a->a_numvals + 1; 892 nnval++; 893 if (a->a_flags & SLAP_ATTR_BIG_MULTI) 894 doff += a->a_numvals; 895 for (i=0; i<a->a_numvals; i++) { 896 int alen = a->a_nvals[i].bv_len + 1 + sizeof(int); 897 len += alen; 898 if (!(a->a_flags & SLAP_ATTR_BIG_MULTI)) 899 dlen += alen; 900 } 901 } 902 } 903 /* padding */ 904 dlen = (dlen + sizeof(ID)-1) & ~(sizeof(ID)-1); 905 eh->len = len; 906 eh->dlen = dlen; 907 eh->nattrs = nat; 908 eh->nvals = nval; 909 eh->offset = nat + nval - nnval - doff; 910 return 0; 911 } 912 913 /* Flag bits for an encoded attribute */ 914 #define MDB_AT_SORTED (1U<<(sizeof(unsigned int)*CHAR_BIT-1)) 915 /* the values are in sorted order */ 916 #define MDB_AT_MULTI (1<<(sizeof(unsigned int)*CHAR_BIT-2)) 917 /* the values of this multi-valued attr are stored separately */ 918 919 #define MDB_AT_NVALS (1U<<(sizeof(unsigned int)*CHAR_BIT-1)) 920 /* this attribute has normalized values */ 921 922 /* Flatten an Entry into a buffer. The buffer starts with the count of the 923 * number of attributes in the entry, the total number of values in the 924 * entry, and the e_ocflags. It then contains a list of integers for each 925 * attribute. For each attribute the first integer gives the index of the 926 * matching AttributeDescription, followed by the number of values in the 927 * attribute. If the MDB_AT_SORTED bit of the attr index is set, the 928 * attribute's values are already sorted. If the MDB_AT_MULTI bit of the 929 * attr index is set, the values are stored separately. 930 * 931 * If the MDB_AT_NVALS bit of numvals is set, the attribute also has 932 * normalized values present. (Note - a_numvals is an unsigned int, so this 933 * means it's possible to receive an attribute that we can't encode due 934 * to size overflow. In practice, this should not be an issue.) 935 * 936 * Then the length of each value is listed. If there are normalized values, 937 * their lengths come next. This continues for each attribute. After all 938 * of the lengths for the last attribute, the actual values are copied, 939 * with a NUL terminator after each value. 940 * The buffer is padded to the sizeof(ID). The entire buffer size is 941 * precomputed so that a single malloc can be performed. 942 */ 943 static int mdb_entry_encode(Operation *op, Entry *e, MDB_val *data, Ecount *eh) 944 { 945 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; 946 ber_len_t i; 947 Attribute *a; 948 unsigned char *ptr; 949 unsigned int *lp, l; 950 951 Debug( LDAP_DEBUG_TRACE, "=> mdb_entry_encode(0x%08lx): %s\n", 952 (long) e->e_id, e->e_dn ); 953 954 /* make sure e->e_ocflags is set */ 955 if (is_entry_referral(e)) 956 ; /* empty */ 957 958 lp = (unsigned int *)data->mv_data; 959 *lp++ = eh->nattrs; 960 *lp++ = eh->nvals; 961 *lp++ = (unsigned int)e->e_ocflags; 962 *lp++ = eh->offset; 963 ptr = (unsigned char *)(lp + eh->offset); 964 965 for (a=e->e_attrs; a; a=a->a_next) { 966 if (!a->a_desc->ad_index) 967 return LDAP_UNDEFINED_TYPE; 968 l = mdb->mi_adxs[a->a_desc->ad_index]; 969 if (a->a_flags & SLAP_ATTR_BIG_MULTI) 970 l |= MDB_AT_MULTI; 971 if (a->a_flags & SLAP_ATTR_SORTED_VALS) 972 l |= MDB_AT_SORTED; 973 *lp++ = l; 974 l = a->a_numvals; 975 if (a->a_nvals != a->a_vals) 976 l |= MDB_AT_NVALS; 977 *lp++ = l; 978 if (a->a_flags & SLAP_ATTR_BIG_MULTI) { 979 continue; 980 } else { 981 if (a->a_vals) { 982 for (i=0; a->a_vals[i].bv_val; i++); 983 assert( i == a->a_numvals ); 984 for (i=0; i<a->a_numvals; i++) { 985 *lp++ = a->a_vals[i].bv_len; 986 memcpy(ptr, a->a_vals[i].bv_val, 987 a->a_vals[i].bv_len); 988 ptr += a->a_vals[i].bv_len; 989 *ptr++ = '\0'; 990 } 991 if (a->a_nvals != a->a_vals) { 992 for (i=0; i<a->a_numvals; i++) { 993 *lp++ = a->a_nvals[i].bv_len; 994 memcpy(ptr, a->a_nvals[i].bv_val, 995 a->a_nvals[i].bv_len); 996 ptr += a->a_nvals[i].bv_len; 997 *ptr++ = '\0'; 998 } 999 } 1000 } 1001 } 1002 } 1003 1004 Debug( LDAP_DEBUG_TRACE, "<= mdb_entry_encode(0x%08lx): %s\n", 1005 (long) e->e_id, e->e_dn ); 1006 1007 return 0; 1008 } 1009 1010 /* Retrieve an Entry that was stored using entry_encode above. 1011 * 1012 * Note: everything is stored in a single contiguous block, so 1013 * you can not free individual attributes or names from this 1014 * structure. Attempting to do so will likely corrupt memory. 1015 */ 1016 1017 int mdb_entry_decode(Operation *op, MDB_txn *txn, MDB_val *data, ID id, Entry **e) 1018 { 1019 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; 1020 int i, j, nattrs, nvals; 1021 int rc; 1022 Attribute *a; 1023 Entry *x; 1024 const char *text; 1025 unsigned int *lp = (unsigned int *)data->mv_data; 1026 unsigned char *ptr; 1027 BerVarray bptr; 1028 MDB_cursor *mvc = NULL; 1029 1030 Debug( LDAP_DEBUG_TRACE, 1031 "=> mdb_entry_decode:\n" ); 1032 1033 nattrs = *lp++; 1034 nvals = *lp++; 1035 x = mdb_entry_alloc(op, nattrs, nvals); 1036 x->e_ocflags = *lp++; 1037 if (!nvals) { 1038 goto done; 1039 } 1040 a = x->e_attrs; 1041 bptr = a->a_vals; 1042 i = *lp++; 1043 ptr = (unsigned char *)(lp + i); 1044 1045 for (;nattrs>0; nattrs--) { 1046 int have_nval = 0, multi = 0; 1047 a->a_flags = SLAP_ATTR_DONT_FREE_DATA | SLAP_ATTR_DONT_FREE_VALS; 1048 i = *lp++; 1049 if (i & MDB_AT_SORTED) { 1050 i ^= MDB_AT_SORTED; 1051 a->a_flags |= SLAP_ATTR_SORTED_VALS; 1052 } 1053 if (i & MDB_AT_MULTI) { 1054 i ^= MDB_AT_MULTI; 1055 a->a_flags |= SLAP_ATTR_BIG_MULTI; 1056 multi = 1; 1057 } 1058 if (i > mdb->mi_numads) { 1059 rc = mdb_ad_read(mdb, txn); 1060 if (rc) 1061 goto leave; 1062 if (i > mdb->mi_numads) { 1063 Debug( LDAP_DEBUG_ANY, 1064 "mdb_entry_decode: attribute index %d not recognized\n", 1065 i ); 1066 rc = LDAP_OTHER; 1067 goto leave; 1068 } 1069 } 1070 a->a_desc = mdb->mi_ads[i]; 1071 a->a_numvals = *lp++; 1072 if (a->a_numvals & MDB_AT_NVALS) { 1073 a->a_numvals ^= MDB_AT_NVALS; 1074 have_nval = 1; 1075 } 1076 a->a_vals = bptr; 1077 if (multi) { 1078 if (!mvc) { 1079 rc = mdb_cursor_open(txn, mdb->mi_dbis[MDB_ID2VAL], &mvc); 1080 if (rc) 1081 goto leave; 1082 } 1083 i = a->a_numvals; 1084 mdb_mval_get(op, mvc, id, a, have_nval); 1085 bptr += i + 1; 1086 if (have_nval) 1087 bptr += i + 1; 1088 } else { 1089 for (i=0; i<a->a_numvals; i++) { 1090 bptr->bv_len = *lp++; 1091 bptr->bv_val = (char *)ptr; 1092 ptr += bptr->bv_len+1; 1093 bptr++; 1094 } 1095 bptr->bv_val = NULL; 1096 bptr->bv_len = 0; 1097 bptr++; 1098 1099 if (have_nval) { 1100 a->a_nvals = bptr; 1101 for (i=0; i<a->a_numvals; i++) { 1102 bptr->bv_len = *lp++; 1103 bptr->bv_val = (char *)ptr; 1104 ptr += bptr->bv_len+1; 1105 bptr++; 1106 } 1107 bptr->bv_val = NULL; 1108 bptr->bv_len = 0; 1109 bptr++; 1110 } else { 1111 a->a_nvals = a->a_vals; 1112 } 1113 } 1114 1115 /* FIXME: This is redundant once a sorted entry is saved into the DB */ 1116 if (( a->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) 1117 && !(a->a_flags & SLAP_ATTR_SORTED_VALS)) { 1118 rc = slap_sort_vals( (Modifications *)a, &text, &j, NULL ); 1119 if ( rc == LDAP_SUCCESS ) { 1120 a->a_flags |= SLAP_ATTR_SORTED_VALS; 1121 } else if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) { 1122 /* should never happen */ 1123 Debug( LDAP_DEBUG_ANY, 1124 "mdb_entry_decode: attributeType %s value #%d provided more than once\n", 1125 a->a_desc->ad_cname.bv_val, j ); 1126 goto leave; 1127 } 1128 } 1129 a->a_next = a+1; 1130 a = a->a_next; 1131 } 1132 a[-1].a_next = NULL; 1133 done: 1134 Debug(LDAP_DEBUG_TRACE, "<= mdb_entry_decode\n" ); 1135 *e = x; 1136 rc = 0; 1137 1138 leave: 1139 if (mvc) 1140 mdb_cursor_close(mvc); 1141 return rc; 1142 } 1143