1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2009 Oracle. All rights reserved. 5 * 6 */ 7using System; 8using System.Collections.Generic; 9using System.Runtime.InteropServices; 10using System.Text; 11using BerkeleyDB.Internal; 12 13namespace BerkeleyDB { 14 /// <summary> 15 /// A class representing a BTreeDatabase. The Btree format is a 16 /// representation of a sorted, balanced tree structure. 17 /// </summary> 18 public class BTreeDatabase : Database { 19 private BTreeCompressDelegate compressHandler; 20 private BTreeDecompressDelegate decompressHandler; 21 private EntryComparisonDelegate compareHandler, prefixCompareHandler; 22 private EntryComparisonDelegate dupCompareHandler; 23 private BDB_CompareDelegate doCompareRef; 24 private BDB_CompareDelegate doPrefixCompareRef; 25 private BDB_CompareDelegate doDupCompareRef; 26 private BDB_CompressDelegate doCompressRef; 27 private BDB_DecompressDelegate doDecompressRef; 28 29 #region Constructors 30 private BTreeDatabase(DatabaseEnvironment env, uint flags) 31 : base(env, flags) { } 32 internal BTreeDatabase(BaseDatabase clone) : base(clone) { } 33 34 private void Config(BTreeDatabaseConfig cfg) { 35 base.Config(cfg); 36 /* 37 * Database.Config calls set_flags, but that doesn't get the BTree 38 * specific flags. No harm in calling it again. 39 */ 40 db.set_flags(cfg.flags); 41 42 if (cfg.BTreeCompare != null) 43 Compare = cfg.BTreeCompare; 44 45 if (cfg.BTreePrefixCompare != null) 46 PrefixCompare = cfg.BTreePrefixCompare; 47 48 // The duplicate comparison function cannot change. 49 if (cfg.DuplicateCompare != null) 50 DupCompare = cfg.DuplicateCompare; 51 52 if (cfg.minkeysIsSet) 53 db.set_bt_minkey(cfg.MinKeysPerPage); 54 55 if (cfg.compressionIsSet) { 56 Compress = cfg.Compress; 57 Decompress = cfg.Decompress; 58 if (Compress == null) 59 doCompressRef = null; 60 else 61 doCompressRef = new BDB_CompressDelegate(doCompress); 62 if (Decompress == null) 63 doDecompressRef = null; 64 else 65 doDecompressRef = new BDB_DecompressDelegate(doDecompress); 66 db.set_bt_compress(doCompressRef, doDecompressRef); 67 } 68 } 69 70 /// <summary> 71 /// Instantiate a new BTreeDatabase object and open the database 72 /// represented by <paramref name="Filename"/>. 73 /// </summary> 74 /// <remarks> 75 /// <para> 76 /// If <paramref name="Filename"/> is null, the database is strictly 77 /// temporary and cannot be opened by any other thread of control, thus 78 /// the database can only be accessed by sharing the single database 79 /// object that created it, in circumstances where doing so is safe. 80 /// </para> 81 /// <para> 82 /// If <see cref="DatabaseConfig.AutoCommit"/> is set, the operation 83 /// will be implicitly transaction protected. Note that transactionally 84 /// protected operations on a datbase object requires the object itself 85 /// be transactionally protected during its open. 86 /// </para> 87 /// </remarks> 88 /// <param name="Filename"> 89 /// The name of an underlying file that will be used to back the 90 /// database. In-memory databases never intended to be preserved on disk 91 /// may be created by setting this parameter to null. 92 /// </param> 93 /// <param name="cfg">The database's configuration</param> 94 /// <returns>A new, open database object</returns> 95 public static BTreeDatabase Open( 96 string Filename, BTreeDatabaseConfig cfg) { 97 return Open(Filename, null, cfg, null); 98 } 99 /// <summary> 100 /// Instantiate a new BTreeDatabase object and open the database 101 /// represented by <paramref name="Filename"/> and 102 /// <paramref name="DatabaseName"/>. 103 /// </summary> 104 /// <remarks> 105 /// <para> 106 /// If both <paramref name="Filename"/> and 107 /// <paramref name="DatabaseName"/> are null, the database is strictly 108 /// temporary and cannot be opened by any other thread of control, thus 109 /// the database can only be accessed by sharing the single database 110 /// object that created it, in circumstances where doing so is safe. If 111 /// <paramref name="Filename"/> is null and 112 /// <paramref name="DatabaseName"/> is non-null, the database can be 113 /// opened by other threads of control and will be replicated to client 114 /// sites in any replication group. 115 /// </para> 116 /// <para> 117 /// If <see cref="DatabaseConfig.AutoCommit"/> is set, the operation 118 /// will be implicitly transaction protected. Note that transactionally 119 /// protected operations on a datbase object requires the object itself 120 /// be transactionally protected during its open. 121 /// </para> 122 /// </remarks> 123 /// <param name="Filename"> 124 /// The name of an underlying file that will be used to back the 125 /// database. In-memory databases never intended to be preserved on disk 126 /// may be created by setting this parameter to null. 127 /// </param> 128 /// <param name="DatabaseName"> 129 /// This parameter allows applications to have multiple databases in a 130 /// single file. Although no DatabaseName needs to be specified, it is 131 /// an error to attempt to open a second database in a file that was not 132 /// initially created using a database name. 133 /// </param> 134 /// <param name="cfg">The database's configuration</param> 135 /// <returns>A new, open database object</returns> 136 public static BTreeDatabase Open( 137 string Filename, string DatabaseName, BTreeDatabaseConfig cfg) { 138 return Open(Filename, DatabaseName, cfg, null); 139 } 140 /// <summary> 141 /// Instantiate a new BTreeDatabase object and open the database 142 /// represented by <paramref name="Filename"/>. 143 /// </summary> 144 /// <remarks> 145 /// <para> 146 /// If <paramref name="Filename"/> is null, the database is strictly 147 /// temporary and cannot be opened by any other thread of control, thus 148 /// the database can only be accessed by sharing the single database 149 /// object that created it, in circumstances where doing so is safe. 150 /// </para> 151 /// <para> 152 /// If <paramref name="txn"/> is null, but 153 /// <see cref="DatabaseConfig.AutoCommit"/> is set, the operation will 154 /// be implicitly transaction protected. Note that transactionally 155 /// protected operations on a datbase object requires the object itself 156 /// be transactionally protected during its open. Also note that the 157 /// transaction must be committed before the object is closed. 158 /// </para> 159 /// </remarks> 160 /// <param name="Filename"> 161 /// The name of an underlying file that will be used to back the 162 /// database. In-memory databases never intended to be preserved on disk 163 /// may be created by setting this parameter to null. 164 /// </param> 165 /// <param name="cfg">The database's configuration</param> 166 /// <param name="txn"> 167 /// If the operation is part of an application-specified transaction, 168 /// <paramref name="txn"/> is a Transaction object returned from 169 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 170 /// the operation is part of a Berkeley DB Concurrent Data Store group, 171 /// <paramref name="txn"/> is a handle returned from 172 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 173 /// </param> 174 /// <returns>A new, open database object</returns> 175 public static BTreeDatabase Open( 176 string Filename, BTreeDatabaseConfig cfg, Transaction txn) { 177 return Open(Filename, null, cfg, txn); 178 } 179 /// <summary> 180 /// Instantiate a new BTreeDatabase object and open the database 181 /// represented by <paramref name="Filename"/> and 182 /// <paramref name="DatabaseName"/>. 183 /// </summary> 184 /// <remarks> 185 /// <para> 186 /// If both <paramref name="Filename"/> and 187 /// <paramref name="DatabaseName"/> are null, the database is strictly 188 /// temporary and cannot be opened by any other thread of control, thus 189 /// the database can only be accessed by sharing the single database 190 /// object that created it, in circumstances where doing so is safe. If 191 /// <paramref name="Filename"/> is null and 192 /// <paramref name="DatabaseName"/> is non-null, the database can be 193 /// opened by other threads of control and will be replicated to client 194 /// sites in any replication group. 195 /// </para> 196 /// <para> 197 /// If <paramref name="txn"/> is null, but 198 /// <see cref="DatabaseConfig.AutoCommit"/> is set, the operation will 199 /// be implicitly transaction protected. Note that transactionally 200 /// protected operations on a datbase object requires the object itself 201 /// be transactionally protected during its open. Also note that the 202 /// transaction must be committed before the object is closed. 203 /// </para> 204 /// </remarks> 205 /// <param name="Filename"> 206 /// The name of an underlying file that will be used to back the 207 /// database. In-memory databases never intended to be preserved on disk 208 /// may be created by setting this parameter to null. 209 /// </param> 210 /// <param name="DatabaseName"> 211 /// This parameter allows applications to have multiple databases in a 212 /// single file. Although no DatabaseName needs to be specified, it is 213 /// an error to attempt to open a second database in a file that was not 214 /// initially created using a database name. 215 /// </param> 216 /// <param name="cfg">The database's configuration</param> 217 /// <param name="txn"> 218 /// If the operation is part of an application-specified transaction, 219 /// <paramref name="txn"/> is a Transaction object returned from 220 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 221 /// the operation is part of a Berkeley DB Concurrent Data Store group, 222 /// <paramref name="txn"/> is a handle returned from 223 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 224 /// </param> 225 /// <returns>A new, open database object</returns> 226 public static BTreeDatabase Open(string Filename, 227 string DatabaseName, BTreeDatabaseConfig cfg, Transaction txn) { 228 BTreeDatabase ret = new BTreeDatabase(cfg.Env, 0); 229 ret.Config(cfg); 230 ret.db.open(Transaction.getDB_TXN(txn), 231 Filename, DatabaseName, DBTYPE.DB_BTREE, cfg.openFlags, 0); 232 ret.isOpen = true; 233 return ret; 234 } 235 #endregion Constructors 236 237 #region Callbacks 238 private static int doCompare(IntPtr dbp, IntPtr dbtp1, IntPtr dbtp2) { 239 DB db = new DB(dbp, false); 240 DBT dbt1 = new DBT(dbtp1, false); 241 DBT dbt2 = new DBT(dbtp2, false); 242 BTreeDatabase btdb = (BTreeDatabase)(db.api_internal); 243 return btdb.Compare( 244 DatabaseEntry.fromDBT(dbt1), DatabaseEntry.fromDBT(dbt2)); 245 } 246 private static int doCompress(IntPtr dbp, IntPtr prevKeyp, 247 IntPtr prevDatap, IntPtr keyp, IntPtr datap, IntPtr destp) { 248 DB db = new DB(dbp, false); 249 DatabaseEntry prevKey = 250 DatabaseEntry.fromDBT(new DBT(prevKeyp, false)); 251 DatabaseEntry prevData = 252 DatabaseEntry.fromDBT(new DBT(prevDatap, false)); 253 DatabaseEntry key = DatabaseEntry.fromDBT(new DBT(keyp, false)); 254 DatabaseEntry data = DatabaseEntry.fromDBT(new DBT(datap, false)); 255 DBT dest = new DBT(destp, false); 256 BTreeDatabase btdb = (BTreeDatabase)(db.api_internal); 257 byte[] arr = new byte[(int)dest.ulen]; 258 int len; 259 try { 260 if (btdb.Compress(prevKey, prevData, key, data, ref arr, out len)) { 261 Marshal.Copy(arr, 0, dest.dataPtr, len); 262 dest.size = (uint)len; 263 return 0; 264 } else { 265 return DbConstants.DB_BUFFER_SMALL; 266 } 267 } catch (Exception) { 268 return -1; 269 } 270 } 271 private static int doDecompress(IntPtr dbp, IntPtr prevKeyp, 272 IntPtr prevDatap, IntPtr cmpp, IntPtr destKeyp, IntPtr destDatap) { 273 DB db = new DB(dbp, false); 274 DatabaseEntry prevKey = 275 DatabaseEntry.fromDBT(new DBT(prevKeyp, false)); 276 DatabaseEntry prevData = 277 DatabaseEntry.fromDBT(new DBT(prevDatap, false)); 278 DBT compressed = new DBT(cmpp, false); 279 DBT destKey = new DBT(destKeyp, false); 280 DBT destData = new DBT(destDatap, false); 281 BTreeDatabase btdb = (BTreeDatabase)(db.api_internal); 282 uint size; 283 try { 284 KeyValuePair<DatabaseEntry, DatabaseEntry> kvp = btdb.Decompress(prevKey, prevData, compressed.data, out size); 285 int keylen = kvp.Key.Data.Length; 286 int datalen = kvp.Value.Data.Length; 287 destKey.size = (uint)keylen; 288 destData.size = (uint)datalen; 289 if (keylen > destKey.ulen || 290 datalen > destData.ulen) 291 return DbConstants.DB_BUFFER_SMALL; 292 Marshal.Copy(kvp.Key.Data, 0, destKey.dataPtr, keylen); 293 Marshal.Copy(kvp.Value.Data, 0, destData.dataPtr, datalen); 294 compressed.size = size; 295 return 0; 296 } catch (Exception) { 297 return -1; 298 } 299 } 300 private static int doDupCompare( 301 IntPtr dbp, IntPtr dbt1p, IntPtr dbt2p) { 302 DB db = new DB(dbp, false); 303 DBT dbt1 = new DBT(dbt1p, false); 304 DBT dbt2 = new DBT(dbt2p, false); 305 306 BTreeDatabase btdb = (BTreeDatabase)(db.api_internal); 307 return btdb.DupCompare( 308 DatabaseEntry.fromDBT(dbt1), DatabaseEntry.fromDBT(dbt2)); 309 } 310 private static int doPrefixCompare( 311 IntPtr dbp, IntPtr dbtp1, IntPtr dbtp2) { 312 DB db = new DB(dbp, false); 313 DBT dbt1 = new DBT(dbtp1, false); 314 DBT dbt2 = new DBT(dbtp2, false); 315 BTreeDatabase btdb = (BTreeDatabase)(db.api_internal); 316 return btdb.PrefixCompare( 317 DatabaseEntry.fromDBT(dbt1), DatabaseEntry.fromDBT(dbt2)); 318 } 319 #endregion Callbacks 320 321 #region Properties 322 // Sorted alpha by property name 323 /// <summary> 324 /// The Btree key comparison function. The comparison function is called 325 /// whenever it is necessary to compare a key specified by the 326 /// application with a key currently stored in the tree. 327 /// </summary> 328 public EntryComparisonDelegate Compare { 329 get { return compareHandler; } 330 private set { 331 if (value == null) 332 db.set_bt_compare(null); 333 else if (compareHandler == null) { 334 if (doCompareRef == null) 335 doCompareRef = new BDB_CompareDelegate(doCompare); 336 db.set_bt_compare(doCompareRef); 337 } 338 compareHandler = value; 339 } 340 } 341 342 /// <summary> 343 /// The compression function used to store key/data pairs in the 344 /// database. 345 /// </summary> 346 public BTreeCompressDelegate Compress { 347 get { return compressHandler; } 348 private set { compressHandler = value; } 349 } 350 351 /// <summary> 352 /// The decompression function used to retrieve key/data pairs from the 353 /// database. 354 /// </summary> 355 public BTreeDecompressDelegate Decompress { 356 get { return decompressHandler; } 357 private set { decompressHandler = value; } 358 } 359 360 /// <summary> 361 /// The duplicate data item comparison function. 362 /// </summary> 363 public EntryComparisonDelegate DupCompare { 364 get { return dupCompareHandler; } 365 private set { 366 /* Cannot be called after open. */ 367 if (value == null) 368 db.set_dup_compare(null); 369 else if (dupCompareHandler == null) { 370 if (doDupCompareRef == null) 371 doDupCompareRef = new BDB_CompareDelegate(doDupCompare); 372 db.set_dup_compare(doDupCompareRef); 373 } 374 dupCompareHandler = value; 375 } 376 } 377 /// <summary> 378 /// Whether the insertion of duplicate data items in the database is 379 /// permitted, and whether duplicates items are sorted. 380 /// </summary> 381 public DuplicatesPolicy Duplicates { 382 get { 383 uint flags = 0; 384 db.get_flags(ref flags); 385 if ((flags & DbConstants.DB_DUPSORT) != 0) 386 return DuplicatesPolicy.SORTED; 387 else if ((flags & DbConstants.DB_DUP) != 0) 388 return DuplicatesPolicy.UNSORTED; 389 else 390 return DuplicatesPolicy.NONE; 391 } 392 } 393 394 /// <summary> 395 /// The minimum number of key/data pairs intended to be stored on any 396 /// single Btree leaf page. 397 /// </summary> 398 public uint MinKeysPerPage { 399 get { 400 uint ret = 0; 401 db.get_bt_minkey(ref ret); 402 return ret; 403 } 404 } 405 406 /// <summary> 407 /// The Btree prefix function. The prefix function is used to determine 408 /// the amount by which keys stored on the Btree internal pages can be 409 /// safely truncated without losing their uniqueness. 410 /// </summary> 411 public EntryComparisonDelegate PrefixCompare { 412 get { return prefixCompareHandler; } 413 private set { 414 if (value == null) 415 db.set_bt_prefix(null); 416 else if (prefixCompareHandler == null) { 417 if (doPrefixCompareRef == null) 418 doPrefixCompareRef = 419 new BDB_CompareDelegate(doPrefixCompare); 420 db.set_bt_prefix(doPrefixCompareRef); 421 } 422 prefixCompareHandler = value; 423 } 424 } 425 426 /// <summary> 427 /// If true, this object supports retrieval from the Btree using record 428 /// numbers. 429 /// </summary> 430 public bool RecordNumbers { 431 get { 432 uint flags = 0; 433 db.get_flags(ref flags); 434 return (flags & DbConstants.DB_RECNUM) != 0; 435 } 436 } 437 438 /// <summary> 439 /// If false, empty pages will not be coalesced into higher-level pages. 440 /// </summary> 441 public bool ReverseSplit { 442 get { 443 uint flags = 0; 444 db.get_flags(ref flags); 445 return (flags & DbConstants.DB_REVSPLITOFF) == 0; 446 } 447 } 448 449 #endregion Properties 450 451 #region Methods 452 // Sorted alpha by method name 453 454 /// <summary> 455 /// Compact the database, and optionally return unused database pages to 456 /// the underlying filesystem. 457 /// </summary> 458 /// <remarks> 459 /// If the operation occurs in a transactional database, the operation 460 /// will be implicitly transaction protected using multiple 461 /// transactions. These transactions will be periodically committed to 462 /// avoid locking large sections of the tree. Any deadlocks encountered 463 /// cause the compaction operation to be retried from the point of the 464 /// last transaction commit. 465 /// </remarks> 466 /// <param name="cdata">Compact configuration parameters</param> 467 /// <returns>Compact operation statistics</returns> 468 public CompactData Compact(CompactConfig cdata) { 469 return Compact(cdata, null); 470 } 471 /// <summary> 472 /// Compact the database, and optionally return unused database pages to 473 /// the underlying filesystem. 474 /// </summary> 475 /// <remarks> 476 /// <para> 477 /// If <paramref name="txn"/> is non-null, then the operation is 478 /// performed using that transaction. In this event, large sections of 479 /// the tree may be locked during the course of the transaction. 480 /// </para> 481 /// <para> 482 /// If <paramref name="txn"/> is null, but the operation occurs in a 483 /// transactional database, the operation will be implicitly transaction 484 /// protected using multiple transactions. These transactions will be 485 /// periodically committed to avoid locking large sections of the tree. 486 /// Any deadlocks encountered cause the compaction operation to be 487 /// retried from the point of the last transaction commit. 488 /// </para> 489 /// </remarks> 490 /// <param name="cdata">Compact configuration parameters</param> 491 /// <param name="txn"> 492 /// If the operation is part of an application-specified transaction, 493 /// <paramref name="txn"/> is a Transaction object returned from 494 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 495 /// the operation is part of a Berkeley DB Concurrent Data Store group, 496 /// <paramref name="txn"/> is a handle returned from 497 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 498 /// </param> 499 /// <returns>Compact operation statistics</returns> 500 public CompactData Compact(CompactConfig cdata, Transaction txn) { 501 DatabaseEntry end = null; 502 if (cdata.returnEnd) 503 end = new DatabaseEntry(); 504 505 db.compact(Transaction.getDB_TXN(txn), cdata.start, cdata.stop, 506 CompactConfig.getDB_COMPACT(cdata), cdata.flags, end); 507 return new CompactData(CompactConfig.getDB_COMPACT(cdata), end); 508 } 509 510 /// <summary> 511 /// Create a database cursor. 512 /// </summary> 513 /// <returns>A newly created cursor</returns> 514 public new BTreeCursor Cursor() { 515 return Cursor(new CursorConfig(), null); 516 } 517 /// <summary> 518 /// Create a database cursor with the given configuration. 519 /// </summary> 520 /// <param name="cfg"> 521 /// The configuration properties for the cursor. 522 /// </param> 523 /// <returns>A newly created cursor</returns> 524 public new BTreeCursor Cursor(CursorConfig cfg) { 525 return Cursor(cfg, null); 526 } 527 /// <summary> 528 /// Create a transactionally protected database cursor. 529 /// </summary> 530 /// <param name="txn"> 531 /// The transaction context in which the cursor may be used. 532 /// </param> 533 /// <returns>A newly created cursor</returns> 534 public new BTreeCursor Cursor(Transaction txn) { 535 return Cursor(new CursorConfig(), txn); 536 } 537 /// <summary> 538 /// Create a transactionally protected database cursor with the given 539 /// configuration. 540 /// </summary> 541 /// <param name="cfg"> 542 /// The configuration properties for the cursor. 543 /// </param> 544 /// <param name="txn"> 545 /// The transaction context in which the cursor may be used. 546 /// </param> 547 /// <returns>A newly created cursor</returns> 548 public new BTreeCursor Cursor(CursorConfig cfg, Transaction txn) { 549 return new BTreeCursor( 550 db.cursor(Transaction.getDB_TXN(txn), cfg.flags), Pagesize); 551 } 552 553 /// <summary> 554 /// Return the database statistical information which does not require 555 /// traversal of the database. 556 /// </summary> 557 /// <returns> 558 /// The database statistical information which does not require 559 /// traversal of the database. 560 /// </returns> 561 public BTreeStats FastStats() { 562 return Stats(null, true, Isolation.DEGREE_THREE); 563 } 564 /// <summary> 565 /// Return the database statistical information which does not require 566 /// traversal of the database. 567 /// </summary> 568 /// <param name="txn"> 569 /// If the operation is part of an application-specified transaction, 570 /// <paramref name="txn"/> is a Transaction object returned from 571 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 572 /// the operation is part of a Berkeley DB Concurrent Data Store group, 573 /// <paramref name="txn"/> is a handle returned from 574 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 575 /// </param> 576 /// <returns> 577 /// The database statistical information which does not require 578 /// traversal of the database. 579 /// </returns> 580 public BTreeStats FastStats(Transaction txn) { 581 return Stats(txn, true, Isolation.DEGREE_THREE); 582 } 583 /// <summary> 584 /// Return the database statistical information which does not require 585 /// traversal of the database. 586 /// </summary> 587 /// <overloads> 588 /// <para> 589 /// Among other things, this method makes it possible for applications 590 /// to request key and record counts without incurring the performance 591 /// penalty of traversing the entire database. 592 /// </para> 593 /// <para> 594 /// The statistical information is described by the 595 /// <see cref="BTreeStats"/>, <see cref="HashStats"/>, 596 /// <see cref="QueueStats"/>, and <see cref="RecnoStats"/> classes. 597 /// </para> 598 /// </overloads> 599 /// <param name="txn"> 600 /// If the operation is part of an application-specified transaction, 601 /// <paramref name="txn"/> is a Transaction object returned from 602 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 603 /// the operation is part of a Berkeley DB Concurrent Data Store group, 604 /// <paramref name="txn"/> is a handle returned from 605 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 606 /// </param> 607 /// <param name="isoDegree"> 608 /// The level of isolation for database reads. 609 /// <see cref="Isolation.DEGREE_ONE"/> will be silently ignored for 610 /// databases which did not specify 611 /// <see cref="DatabaseConfig.ReadUncommitted"/>. 612 /// </param> 613 /// <returns> 614 /// The database statistical information which does not require 615 /// traversal of the database. 616 /// </returns> 617 public BTreeStats FastStats(Transaction txn, Isolation isoDegree) { 618 return Stats(txn, true, isoDegree); 619 } 620 621 /// <summary> 622 /// Retrieve a specific numbered key/data pair from the database. 623 /// </summary> 624 /// <param name="recno"> 625 /// The record number of the record to be retrieved. 626 /// </param> 627 /// <returns> 628 /// A <see cref="KeyValuePair{T,T}"/> whose Key 629 /// parameter is <paramref name="key"/> and whose Value parameter is the 630 /// retrieved data. 631 /// </returns> 632 public KeyValuePair<DatabaseEntry, DatabaseEntry> Get(uint recno) { 633 return Get(recno, null, null); 634 } 635 /// <summary> 636 /// Retrieve a specific numbered key/data pair from the database. 637 /// </summary> 638 /// <param name="recno"> 639 /// The record number of the record to be retrieved. 640 /// </param> 641 /// <param name="txn"> 642 /// <paramref name="txn"/> is a Transaction object returned from 643 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 644 /// the operation is part of a Berkeley DB Concurrent Data Store group, 645 /// <paramref name="txn"/> is a handle returned from 646 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 647 /// </param> 648 /// <returns> 649 /// A <see cref="KeyValuePair{T,T}"/> whose Key 650 /// parameter is <paramref name="key"/> and whose Value parameter is the 651 /// retrieved data. 652 /// </returns> 653 public KeyValuePair<DatabaseEntry, DatabaseEntry> Get( 654 uint recno, Transaction txn) { 655 return Get(recno, txn, null); 656 } 657 /// <summary> 658 /// Retrieve a specific numbered key/data pair from the database. 659 /// </summary> 660 /// <param name="recno"> 661 /// The record number of the record to be retrieved. 662 /// </param> 663 /// <param name="txn"> 664 /// <paramref name="txn"/> is a Transaction object returned from 665 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 666 /// the operation is part of a Berkeley DB Concurrent Data Store group, 667 /// <paramref name="txn"/> is a handle returned from 668 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 669 /// </param> 670 /// <param name="info">The locking behavior to use.</param> 671 /// <returns> 672 /// A <see cref="KeyValuePair{T,T}"/> whose Key 673 /// parameter is <paramref name="key"/> and whose Value parameter is the 674 /// retrieved data. 675 /// </returns> 676 public KeyValuePair<DatabaseEntry, DatabaseEntry> Get( 677 uint recno, Transaction txn, LockingInfo info) { 678 DatabaseEntry key = new DatabaseEntry(); 679 key.Data = BitConverter.GetBytes(recno); 680 681 return Get(key, null, txn, info, DbConstants.DB_SET_RECNO); 682 } 683 684 public KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> GetMultiple( 685 uint recno) { 686 return GetMultiple(recno, (int)Pagesize, null, null); 687 } 688 public KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> GetMultiple( 689 uint recno, int BufferSize) { 690 return GetMultiple(recno, BufferSize, null, null); 691 } 692 public KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> GetMultiple( 693 uint recno, int BufferSize, Transaction txn) { 694 return GetMultiple(recno, BufferSize, txn, null); 695 } 696 public KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> GetMultiple( 697 uint recno, int BufferSize, Transaction txn, LockingInfo info) { 698 KeyValuePair<DatabaseEntry, DatabaseEntry> kvp; 699 700 DatabaseEntry key = new DatabaseEntry(); 701 key.Data = BitConverter.GetBytes(recno); 702 703 DatabaseEntry data = new DatabaseEntry(); 704 705 for (; ; ) { 706 data.UserData = new byte[BufferSize]; 707 try { 708 kvp = Get(key, data, txn, info, 709 DbConstants.DB_MULTIPLE | DbConstants.DB_SET_RECNO); 710 break; 711 } catch (MemoryException) { 712 int sz = (int)data.size; 713 if (sz > BufferSize) 714 BufferSize = sz; 715 else 716 BufferSize *= 2; 717 } 718 } 719 MultipleDatabaseEntry dbe = new MultipleDatabaseEntry(kvp.Value); 720 return new KeyValuePair<DatabaseEntry, MultipleDatabaseEntry>( 721 kvp.Key, dbe); 722 } 723 724 /// <summary> 725 /// Return an estimate of the proportion of keys that are less than, 726 /// equal to, and greater than the specified key. 727 /// </summary> 728 /// <param name="key">The key to search for</param> 729 /// <returns> 730 /// An estimate of the proportion of keys that are less than, equal to, 731 /// and greater than the specified key. 732 /// </returns> 733 public KeyRange KeyRange(DatabaseEntry key) { 734 return KeyRange(key, null); 735 } 736 /// <summary> 737 /// Return an estimate of the proportion of keys that are less than, 738 /// equal to, and greater than the specified key. 739 /// </summary> 740 /// <param name="key">The key to search for</param> 741 /// <param name="txn"> 742 /// If the operation is part of an application-specified transaction, 743 /// <paramref name="txn"/> is a Transaction object returned from 744 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 745 /// the operation is part of a Berkeley DB Concurrent Data Store group, 746 /// <paramref name="txn"/> is a handle returned from 747 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 748 /// </param> 749 /// <returns> 750 /// An estimate of the proportion of keys that are less than, equal to, 751 /// and greater than the specified key. 752 /// </returns> 753 public KeyRange KeyRange(DatabaseEntry key, Transaction txn) { 754 DB_KEY_RANGE range = new DB_KEY_RANGE(); 755 db.key_range(Transaction.getDB_TXN(txn), key, range, 0); 756 return new KeyRange(range); 757 } 758 759 /// <summary> 760 /// Store the key/data pair in the database only if it does not already 761 /// appear in the database. 762 /// </summary> 763 /// <param name="key">The key to store in the database</param> 764 /// <param name="data">The data item to store in the database</param> 765 public void PutNoDuplicate(DatabaseEntry key, DatabaseEntry data) { 766 PutNoDuplicate(key, data, null); 767 } 768 /// <summary> 769 /// Store the key/data pair in the database only if it does not already 770 /// appear in the database. 771 /// </summary> 772 /// <param name="key">The key to store in the database</param> 773 /// <param name="data">The data item to store in the database</param> 774 /// <param name="txn"> 775 /// If the operation is part of an application-specified transaction, 776 /// <paramref name="txn"/> is a Transaction object returned from 777 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 778 /// the operation is part of a Berkeley DB Concurrent Data Store group, 779 /// <paramref name="txn"/> is a handle returned from 780 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 781 /// </param> 782 public void PutNoDuplicate( 783 DatabaseEntry key, DatabaseEntry data, Transaction txn) { 784 Put(key, data, txn, DbConstants.DB_NODUPDATA); 785 } 786 787 /// <summary> 788 /// Return the database statistical information for this database. 789 /// </summary> 790 /// <returns>Database statistical information.</returns> 791 public BTreeStats Stats() { 792 return Stats(null, false, Isolation.DEGREE_THREE); 793 } 794 /// <summary> 795 /// Return the database statistical information for this database. 796 /// </summary> 797 /// <param name="txn"> 798 /// If the operation is part of an application-specified transaction, 799 /// <paramref name="txn"/> is a Transaction object returned from 800 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 801 /// the operation is part of a Berkeley DB Concurrent Data Store group, 802 /// <paramref name="txn"/> is a handle returned from 803 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 804 /// </param> 805 /// <returns>Database statistical information.</returns> 806 public BTreeStats Stats(Transaction txn) { 807 return Stats(txn, false, Isolation.DEGREE_THREE); 808 } 809 /// <summary> 810 /// Return the database statistical information for this database. 811 /// </summary> 812 /// <overloads> 813 /// The statistical information is described by 814 /// <see cref="BTreeStats"/>. 815 /// </overloads> 816 /// <param name="txn"> 817 /// If the operation is part of an application-specified transaction, 818 /// <paramref name="txn"/> is a Transaction object returned from 819 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 820 /// the operation is part of a Berkeley DB Concurrent Data Store group, 821 /// <paramref name="txn"/> is a handle returned from 822 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 823 /// </param> 824 /// <param name="isoDegree"> 825 /// The level of isolation for database reads. 826 /// <see cref="Isolation.DEGREE_ONE"/> will be silently ignored for 827 /// databases which did not specify 828 /// <see cref="DatabaseConfig.ReadUncommitted"/>. 829 /// </param> 830 /// <returns>Database statistical information.</returns> 831 public BTreeStats Stats(Transaction txn, Isolation isoDegree) { 832 return Stats(txn, false, isoDegree); 833 } 834 private BTreeStats Stats( 835 Transaction txn, bool fast, Isolation isoDegree) { 836 uint flags = 0; 837 flags |= fast ? DbConstants.DB_FAST_STAT : 0; 838 switch (isoDegree) { 839 case Isolation.DEGREE_ONE: 840 flags |= DbConstants.DB_READ_UNCOMMITTED; 841 break; 842 case Isolation.DEGREE_TWO: 843 flags |= DbConstants.DB_READ_COMMITTED; 844 break; 845 } 846 BTreeStatStruct st = db.stat_bt(Transaction.getDB_TXN(txn), flags); 847 return new BTreeStats(st); 848 } 849 850 /// <summary> 851 /// Return pages to the filesystem that are already free and at the end 852 /// of the file. 853 /// </summary> 854 /// <returns> 855 /// The number of database pages returned to the filesystem 856 /// </returns> 857 public uint TruncateUnusedPages() { 858 return TruncateUnusedPages(null); 859 } 860 /// <summary> 861 /// Return pages to the filesystem that are already free and at the end 862 /// of the file. 863 /// </summary> 864 /// <param name="txn"> 865 /// If the operation is part of an application-specified transaction, 866 /// <paramref name="txn"/> is a Transaction object returned from 867 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 868 /// the operation is part of a Berkeley DB Concurrent Data Store group, 869 /// <paramref name="txn"/> is a handle returned from 870 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 871 /// </param> 872 /// <returns> 873 /// The number of database pages returned to the filesystem 874 /// </returns> 875 public uint TruncateUnusedPages(Transaction txn) { 876 DB_COMPACT cdata = new DB_COMPACT(); 877 db.compact(Transaction.getDB_TXN(txn), 878 null, null, cdata, DbConstants.DB_FREELIST_ONLY, null); 879 return cdata.compact_pages_truncated; 880 } 881 882 #endregion Methods 883 } 884} 885