1 /*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2009, 2013 Oracle and/or its affiliates. All rights reserved. 5 * 6 */ 7 using System; 8 using System.Collections.Generic; 9 using System.IO; 10 using System.Text; 11 using BerkeleyDB.Internal; 12 13 namespace BerkeleyDB { 14 /// <summary> 15 /// A class representing a Berkeley DB database, a base class for access 16 /// method specific classes. 17 /// </summary> 18 public class Database : BaseDatabase, IDisposable { 19 private static BDB_FileWriteDelegate writeToFileRef; 20 21 #region Constructors 22 /// <summary> 23 /// Protected constructor 24 /// </summary> 25 /// <param name="env"> 26 /// The environment in which to create this database 27 /// </param> 28 /// <param name="flags">Flags to pass to the DB->create() method</param> Database(DatabaseEnvironment env, uint flags)29 protected Database(DatabaseEnvironment env, uint flags) 30 : base(env, flags) { 31 } 32 /// <summary> 33 /// Create a new database object with the same underlying DB handle as 34 /// <paramref name="clone"/>. Used during Database.Open to get an 35 /// object of the correct DBTYPE. 36 /// </summary> 37 /// <param name="clone">Database to clone</param> Database(BaseDatabase clone)38 protected Database(BaseDatabase clone) : base(clone) { } fromDB(DB dbp)39 internal static Database fromDB(DB dbp) { 40 try { 41 return (Database)dbp.api_internal; 42 } catch { } 43 return null; 44 } 45 46 /// <summary> 47 /// Instantiate a new Database object and open the database represented 48 /// by <paramref name="Filename"/>. The file specified by 49 /// <paramref name="Filename"/> must exist. 50 /// </summary> 51 /// <remarks> 52 /// <para> 53 /// If <see cref="DatabaseConfig.AutoCommit"/> is set, the operation 54 /// will be implicitly transaction protected. Note that transactionally 55 /// protected operations on a datbase object requires the object itself 56 /// be transactionally protected during its open. 57 /// </para> 58 /// </remarks> 59 /// <param name="Filename"> 60 /// The name of an underlying file that will be used to back the 61 /// database. 62 /// </param> 63 /// <param name="cfg">The database's configuration</param> 64 /// <returns>A new, open database object</returns> Open(string Filename, DatabaseConfig cfg)65 public static Database Open(string Filename, DatabaseConfig cfg) { 66 return Open(Filename, null, cfg, null); 67 } 68 /// <summary> 69 /// Instantiate a new Database object and open the database represented 70 /// by <paramref name="Filename"/> and <paramref name="DatabaseName"/>. 71 /// The file specified by <paramref name="Filename"/> must exist. 72 /// </summary> 73 /// <remarks> 74 /// <para> 75 /// If <paramref name="Filename"/> is null and 76 /// <paramref name="DatabaseName"/> is non-null, the database can be 77 /// opened by other threads of control and will be replicated to client 78 /// sites in any replication group. 79 /// </para> 80 /// <para> 81 /// If <see cref="DatabaseConfig.AutoCommit"/> is set, the operation 82 /// will be implicitly transaction protected. Note that transactionally 83 /// protected operations on a datbase object requires the object itself 84 /// be transactionally protected during its open. 85 /// </para> 86 /// </remarks> 87 /// <param name="Filename"> 88 /// The name of an underlying file that will be used to back the 89 /// database. In-memory databases never intended to be preserved on disk 90 /// may be created by setting this parameter to null.</param> 91 /// <param name="DatabaseName"> 92 /// This parameter allows applications to have multiple databases in a 93 /// single file. Although no DatabaseName needs to be specified, it is 94 /// an error to attempt to open a second database in a file that was not 95 /// initially created using a database name. 96 /// </param> 97 /// <param name="cfg">The database's configuration</param> 98 /// <returns>A new, open database object</returns> Open( string Filename, string DatabaseName, DatabaseConfig cfg)99 public static Database Open( 100 string Filename, string DatabaseName, DatabaseConfig cfg) { 101 return Open(Filename, DatabaseName, cfg, null); 102 } 103 /// <summary> 104 /// Instantiate a new Database object and open the database represented 105 /// by <paramref name="Filename"/>. The file specified by 106 /// <paramref name="Filename"/> must exist. 107 /// </summary> 108 /// <remarks> 109 /// <para> 110 /// If <paramref name="Filename"/> is null, the database is strictly 111 /// temporary and cannot be opened by any other thread of control, thus 112 /// the database can only be accessed by sharing the single database 113 /// object that created it, in circumstances where doing so is safe. 114 /// </para> 115 /// <para> 116 /// If <paramref name="txn"/> is null, but 117 /// <see cref="DatabaseConfig.AutoCommit"/> is set, the operation will 118 /// 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. Also note that the 121 /// transaction must be committed before the object is closed. 122 /// </para> 123 /// </remarks> 124 /// <param name="Filename"> 125 /// The name of an underlying file that will be used to back the 126 /// database. In-memory databases never intended to be preserved on disk 127 /// may be created by setting this parameter to null. 128 /// </param> 129 /// <param name="cfg">The database's configuration</param> 130 /// <param name="txn"> 131 /// If the operation is part of an application-specified transaction, 132 /// <paramref name="txn"/> is a Transaction object returned from 133 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 134 /// the operation is part of a Berkeley DB Concurrent Data Store group, 135 /// <paramref name="txn"/> is a handle returned from 136 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 137 /// </param> 138 /// <returns>A new, open database object</returns> Open( string Filename, DatabaseConfig cfg, Transaction txn)139 public static Database Open( 140 string Filename, DatabaseConfig cfg, Transaction txn) { 141 return Open(Filename, null, cfg, txn); 142 } 143 /// <summary> 144 /// Instantiate a new Database object and open the database represented 145 /// by <paramref name="Filename"/> and <paramref name="DatabaseName"/>. 146 /// The file specified by <paramref name="Filename"/> must exist. 147 /// </summary> 148 /// <remarks> 149 /// <para> 150 /// If both <paramref name="Filename"/> and 151 /// <paramref name="DatabaseName"/> are null, the database is strictly 152 /// temporary and cannot be opened by any other thread of control, thus 153 /// the database can only be accessed by sharing the single database 154 /// object that created it, in circumstances where doing so is safe. If 155 /// <paramref name="Filename"/> is null and 156 /// <paramref name="DatabaseName"/> is non-null, the database can be 157 /// opened by other threads of control and will be replicated to client 158 /// sites in any replication group. 159 /// </para> 160 /// <para> 161 /// If <paramref name="txn"/> is null, but 162 /// <see cref="DatabaseConfig.AutoCommit"/> is set, the operation will 163 /// be implicitly transaction protected. Note that transactionally 164 /// protected operations on a datbase object requires the object itself 165 /// be transactionally protected during its open. Also note that the 166 /// transaction must be committed before the object is closed. 167 /// </para> 168 /// </remarks> 169 /// <param name="Filename"> 170 /// The name of an underlying file that will be used to back the 171 /// database. In-memory databases never intended to be preserved on disk 172 /// may be created by setting this parameter to null. 173 /// </param> 174 /// <param name="DatabaseName"> 175 /// This parameter allows applications to have multiple databases in a 176 /// single file. Although no DatabaseName needs to be specified, it is 177 /// an error to attempt to open a second database in a file that was not 178 /// initially created using a database name. 179 /// </param> 180 /// <param name="cfg">The database's configuration</param> 181 /// <param name="txn"> 182 /// If the operation is part of an application-specified transaction, 183 /// <paramref name="txn"/> is a Transaction object returned from 184 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 185 /// the operation is part of a Berkeley DB Concurrent Data Store group, 186 /// <paramref name="txn"/> is a handle returned from 187 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 188 /// </param> 189 /// <returns>A new, open database object</returns> Open(string Filename, string DatabaseName, DatabaseConfig cfg, Transaction txn)190 public static new Database Open(string Filename, 191 string DatabaseName, DatabaseConfig cfg, Transaction txn) { 192 Database ret; 193 BaseDatabase db = BaseDatabase.Open( 194 Filename, DatabaseName, cfg, txn); 195 switch (db.Type.getDBTYPE()) { 196 case DBTYPE.DB_BTREE: 197 ret = new BTreeDatabase(db); 198 break; 199 case DBTYPE.DB_HASH: 200 ret = new HashDatabase(db); 201 break; 202 case DBTYPE.DB_HEAP: 203 ret = new HeapDatabase(db); 204 break; 205 case DBTYPE.DB_QUEUE: 206 ret = new QueueDatabase(db); 207 break; 208 case DBTYPE.DB_RECNO: 209 ret = new RecnoDatabase(db); 210 break; 211 default: 212 throw new DatabaseException(0); 213 } 214 db.Dispose(); 215 ret.isOpen = true; 216 return ret; 217 } 218 #endregion Constructor 219 writeToFile(TextWriter OutputStream, string data)220 private static int writeToFile(TextWriter OutputStream, string data) { 221 OutputStream.Write(data); 222 return 0; 223 } 224 225 #region Methods 226 /// <summary> 227 /// If a key/data pair in the database matches <paramref name="key"/> 228 /// and <paramref name="data"/>, return the key and all duplicate data 229 /// items. 230 /// </summary> 231 /// <param name="key">The key to search for</param> 232 /// <param name="data">The data to search for</param> 233 /// <exception cref="NotFoundException"> 234 /// A NotFoundException is thrown if <paramref name="key"/> and 235 /// <paramref name="data"/> are not in the database. 236 /// </exception> 237 /// <exception cref="KeyEmptyException"> 238 /// A KeyEmptyException is thrown if the database is a 239 /// <see cref="QueueDatabase"/> or <see cref="RecnoDatabase"/> 240 /// database and <paramref name="key"/> exists, but was never explicitly 241 /// created by the application or was later deleted. 242 /// </exception> 243 /// <returns> 244 /// A <see cref="KeyValuePair{T,T}"/> 245 /// whose Key parameter is <paramref name="key"/> and whose Value 246 /// parameter is the retrieved data items. 247 /// </returns> 248 public GetBothMultiple( DatabaseEntry key, DatabaseEntry data)249 KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> GetBothMultiple( 250 DatabaseEntry key, DatabaseEntry data) { 251 /* 252 * Make sure we pass a buffer that's big enough to hold data.Data 253 * and is a multiple of the page size. Cache this.Pagesize to avoid 254 * multiple P/Invoke calls. 255 */ 256 uint pgsz = Pagesize; 257 uint npgs = (data.size / pgsz) + 1; 258 return GetBothMultiple(key, data, (int)(npgs * pgsz), null, null); 259 } 260 /// <summary> 261 /// If a key/data pair in the database matches <paramref name="key"/> 262 /// and <paramref name="data"/>, return the key and all duplicate data 263 /// items. 264 /// </summary> 265 /// <param name="key">The key to search for</param> 266 /// <param name="data">The data to search for</param> 267 /// <param name="BufferSize"> 268 /// The initial size of the buffer to fill with duplicate data items. If 269 /// the buffer is not large enough, it will be automatically resized. 270 /// </param> 271 /// <exception cref="NotFoundException"> 272 /// A NotFoundException is thrown if <paramref name="key"/> and 273 /// <paramref name="data"/> are not in the database. 274 /// </exception> 275 /// <exception cref="KeyEmptyException"> 276 /// A KeyEmptyException is thrown if the database is a 277 /// <see cref="QueueDatabase"/> or <see cref="RecnoDatabase"/> 278 /// database and <paramref name="key"/> exists, but was never explicitly 279 /// created by the application or was later deleted. 280 /// </exception> 281 /// <returns> 282 /// A <see cref="KeyValuePair{T,T}"/> 283 /// whose Key parameter is <paramref name="key"/> and whose Value 284 /// parameter is the retrieved data items. 285 /// </returns> 286 public GetBothMultiple( DatabaseEntry key, DatabaseEntry data, int BufferSize)287 KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> GetBothMultiple( 288 DatabaseEntry key, DatabaseEntry data, int BufferSize) { 289 return GetBothMultiple(key, data, BufferSize, null, null); 290 } 291 /// <summary> 292 /// If a key/data pair in the database matches <paramref name="key"/> 293 /// and <paramref name="data"/>, return the key and all duplicate data 294 /// items. 295 /// </summary> 296 /// <param name="key">The key to search for</param> 297 /// <param name="data">The data to search for</param> 298 /// <param name="BufferSize"> 299 /// The initial size of the buffer to fill with duplicate data items. If 300 /// the buffer is not large enough, it will be automatically resized. 301 /// </param> 302 /// <param name="txn"> 303 /// <paramref name="txn"/> is a Transaction object returned from 304 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 305 /// the operation is part of a Berkeley DB Concurrent Data Store group, 306 /// <paramref name="txn"/> is a handle returned from 307 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 308 /// </param> 309 /// <exception cref="NotFoundException"> 310 /// A NotFoundException is thrown if <paramref name="key"/> and 311 /// <paramref name="data"/> are not in the database. 312 /// </exception> 313 /// <exception cref="KeyEmptyException"> 314 /// A KeyEmptyException is thrown if the database is a 315 /// <see cref="QueueDatabase"/> or <see cref="RecnoDatabase"/> 316 /// database and <paramref name="key"/> exists, but was never explicitly 317 /// created by the application or was later deleted. 318 /// </exception> 319 /// <returns> 320 /// A <see cref="KeyValuePair{T,T}"/> 321 /// whose Key parameter is <paramref name="key"/> and whose Value 322 /// parameter is the retrieved data items. 323 /// </returns> 324 public GetBothMultiple( DatabaseEntry key, DatabaseEntry data, int BufferSize, Transaction txn)325 KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> GetBothMultiple( 326 DatabaseEntry key, 327 DatabaseEntry data, int BufferSize, Transaction txn) { 328 return GetBothMultiple(key, data, BufferSize, txn, null); 329 } 330 /// <summary> 331 /// If a key/data pair in the database matches <paramref name="key"/> 332 /// and <paramref name="data"/>, return the key and all duplicate data 333 /// items. 334 /// </summary> 335 /// <param name="key">The key to search for</param> 336 /// <param name="data">The data to search for</param> 337 /// <param name="BufferSize"> 338 /// The initial size of the buffer to fill with duplicate data items. If 339 /// the buffer is not large enough, it will be automatically resized. 340 /// </param> 341 /// <param name="txn"> 342 /// <paramref name="txn"/> is a Transaction object returned from 343 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 344 /// the operation is part of a Berkeley DB Concurrent Data Store group, 345 /// <paramref name="txn"/> is a handle returned from 346 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 347 /// </param> 348 /// <param name="info">The locking behavior to use.</param> 349 /// <exception cref="NotFoundException"> 350 /// A NotFoundException is thrown if <paramref name="key"/> and 351 /// <paramref name="data"/> are not in the database. 352 /// </exception> 353 /// <exception cref="KeyEmptyException"> 354 /// A KeyEmptyException is thrown if the database is a 355 /// <see cref="QueueDatabase"/> or <see cref="RecnoDatabase"/> 356 /// database and <paramref name="key"/> exists, but was never explicitly 357 /// created by the application or was later deleted. 358 /// </exception> 359 /// <returns> 360 /// A <see cref="KeyValuePair{T,T}"/> 361 /// whose Key parameter is <paramref name="key"/> and whose Value 362 /// parameter is the retrieved data items. 363 /// </returns> 364 public GetBothMultiple( DatabaseEntry key, DatabaseEntry data, int BufferSize, Transaction txn, LockingInfo info)365 KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> GetBothMultiple( 366 DatabaseEntry key, DatabaseEntry data, 367 int BufferSize, Transaction txn, LockingInfo info) { 368 KeyValuePair<DatabaseEntry, DatabaseEntry> kvp; 369 int datasz = (int)data.Data.Length; 370 371 for (; ; ) { 372 byte[] udata = new byte[BufferSize]; 373 Array.Copy(data.Data, udata, datasz); 374 data.UserData = udata; 375 data.size = (uint)datasz; 376 try { 377 kvp = Get(key, data, txn, info, 378 DbConstants.DB_MULTIPLE | DbConstants.DB_GET_BOTH); 379 break; 380 } catch (MemoryException) { 381 int sz = (int)data.size; 382 if (sz > BufferSize) 383 BufferSize = sz; 384 else 385 BufferSize *= 2; 386 } 387 } 388 MultipleDatabaseEntry dbe = new MultipleDatabaseEntry(kvp.Value); 389 return new KeyValuePair<DatabaseEntry, MultipleDatabaseEntry>( 390 kvp.Key, dbe); 391 } 392 393 /// <summary> 394 /// Retrieve a key and all duplicate data items from the database. 395 /// </summary> 396 /// <param name="key">The key to search for</param> 397 /// <exception cref="NotFoundException"> 398 /// A NotFoundException is thrown if <paramref name="key"/> is not in 399 /// the database. 400 /// </exception> 401 /// <exception cref="KeyEmptyException"> 402 /// A KeyEmptyException is thrown if the database is a 403 /// <see cref="QueueDatabase"/> or <see cref="RecnoDatabase"/> 404 /// database and <paramref name="key"/> exists, but was never explicitly 405 /// created by the application or was later deleted. 406 /// </exception> 407 /// <returns> 408 /// A <see cref="KeyValuePair{T,T}"/> 409 /// whose Key parameter is <paramref name="key"/> and whose Value 410 /// parameter is the retrieved data items. 411 /// </returns> GetMultiple( DatabaseEntry key)412 public KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> GetMultiple( 413 DatabaseEntry key) { 414 return GetMultiple(key, (int)Pagesize, null, null); 415 } 416 /// <summary> 417 /// Retrieve a key and all duplicate data items from the database. 418 /// </summary> 419 /// <param name="key">The key to search for</param> 420 /// <param name="BufferSize"> 421 /// The initial size of the buffer to fill with duplicate data items. If 422 /// the buffer is not large enough, it will be automatically resized. 423 /// </param> 424 /// <exception cref="NotFoundException"> 425 /// A NotFoundException is thrown if <paramref name="key"/> is not in 426 /// the database. 427 /// </exception> 428 /// <exception cref="KeyEmptyException"> 429 /// A KeyEmptyException is thrown if the database is a 430 /// <see cref="QueueDatabase"/> or <see cref="RecnoDatabase"/> 431 /// database and <paramref name="key"/> exists, but was never explicitly 432 /// created by the application or was later deleted. 433 /// </exception> 434 /// <returns> 435 /// A <see cref="KeyValuePair{T,T}"/> 436 /// whose Key parameter is <paramref name="key"/> and whose Value 437 /// parameter is the retrieved data items. 438 /// </returns> GetMultiple( DatabaseEntry key, int BufferSize)439 public KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> GetMultiple( 440 DatabaseEntry key, int BufferSize) { 441 return GetMultiple(key, BufferSize, null, null); 442 } 443 /// <summary> 444 /// Retrieve a key and all duplicate data items from the database. 445 /// </summary> 446 /// <param name="key">The key to search for</param> 447 /// <param name="BufferSize"> 448 /// The initial size of the buffer to fill with duplicate data items. If 449 /// the buffer is not large enough, it will be automatically resized. 450 /// </param> 451 /// <param name="txn"> 452 /// <paramref name="txn"/> is a Transaction object returned from 453 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 454 /// the operation is part of a Berkeley DB Concurrent Data Store group, 455 /// <paramref name="txn"/> is a handle returned from 456 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 457 /// </param> 458 /// <returns> 459 /// A <see cref="KeyValuePair{T,T}"/> 460 /// whose Key parameter is <paramref name="key"/> and whose Value 461 /// parameter is the retrieved data items. 462 /// </returns> GetMultiple( DatabaseEntry key, int BufferSize, Transaction txn)463 public KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> GetMultiple( 464 DatabaseEntry key, int BufferSize, Transaction txn) { 465 return GetMultiple(key, BufferSize, txn, null); 466 } 467 /// <summary> 468 /// Retrieve a key and all duplicate data items from the database. 469 /// </summary> 470 /// <param name="key">The key to search for</param> 471 /// <param name="BufferSize"> 472 /// The initial size of the buffer to fill with duplicate data items. If 473 /// the buffer is not large enough, it will be automatically resized. 474 /// </param> 475 /// <param name="txn"> 476 /// <paramref name="txn"/> is a Transaction object returned from 477 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 478 /// the operation is part of a Berkeley DB Concurrent Data Store group, 479 /// <paramref name="txn"/> is a handle returned from 480 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 481 /// </param> 482 /// <param name="info">The locking behavior to use.</param> 483 /// <returns> 484 /// A <see cref="KeyValuePair{T,T}"/> 485 /// whose Key parameter is <paramref name="key"/> and whose Value 486 /// parameter is the retrieved data items. 487 /// </returns> GetMultiple( DatabaseEntry key, int BufferSize, Transaction txn, LockingInfo info)488 public KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> GetMultiple( 489 DatabaseEntry key, 490 int BufferSize, Transaction txn, LockingInfo info) { 491 KeyValuePair<DatabaseEntry, DatabaseEntry> kvp; 492 493 DatabaseEntry data = new DatabaseEntry(); 494 for (; ; ) { 495 data.UserData = new byte[BufferSize]; 496 try { 497 kvp = Get(key, data, txn, info, DbConstants.DB_MULTIPLE); 498 break; 499 } catch (MemoryException) { 500 int sz = (int)data.size; 501 if (sz > BufferSize) 502 BufferSize = sz; 503 else 504 BufferSize *= 2; 505 } 506 } 507 MultipleDatabaseEntry dbe = new MultipleDatabaseEntry(kvp.Value); 508 return new KeyValuePair<DatabaseEntry, MultipleDatabaseEntry>( 509 kvp.Key, dbe); 510 } 511 512 /// <summary> 513 /// Create a specialized join cursor for use in performing equality or 514 /// natural joins on secondary indices. 515 /// </summary> 516 /// <remarks> 517 /// <para> 518 /// Once the cursors have been passed as part of <paramref name="lst"/>, 519 /// they should not be accessed or modified until the newly created 520 /// <see cref="JoinCursor"/>has been closed, or else inconsistent 521 /// results may be returned. 522 /// </para> 523 /// <para> 524 /// Joined values are retrieved by doing a sequential iteration over the 525 /// first cursor in <paramref name="lst"/>, and a nested iteration over 526 /// each secondary cursor in the order they are specified in the 527 /// curslist parameter. This requires database traversals to search for 528 /// the current datum in all the cursors after the first. For this 529 /// reason, the best join performance normally results from sorting the 530 /// cursors from the one that refers to the least number of data items 531 /// to the one that refers to the most. 532 /// </para> 533 /// </remarks> 534 /// <param name="lst"> 535 /// An array of SecondaryCursors. Each cursor must have been initialized 536 /// to refer to the key on which the underlying database should be 537 /// joined. 538 /// </param> 539 /// <param name="sortCursors"> 540 /// If true, sort the cursors from the one that refers to the least 541 /// number of data items to the one that refers to the most. If the 542 /// data are structured so that cursors with many data items also share 543 /// many common elements, higher performance will result from listing 544 /// those cursors before cursors with fewer data items; that is, a sort 545 /// order other than the default. A setting of false permits 546 /// applications to perform join optimization prior to calling Join. 547 /// </param> 548 /// <returns> 549 /// A specialized join cursor for use in performing equality or natural 550 /// joins on secondary indices. 551 /// </returns> Join(SecondaryCursor[] lst, bool sortCursors)552 public JoinCursor Join(SecondaryCursor[] lst, bool sortCursors) { 553 int i; 554 IntPtr[] cursList = new IntPtr[lst.Length + 1]; 555 for (i = 0; i < lst.Length; i++) 556 cursList[i] = DBC.getCPtr( 557 SecondaryCursor.getDBC(lst[i])).Handle; 558 cursList[i] = IntPtr.Zero; 559 return new JoinCursor(db.join(cursList, 560 sortCursors ? 0 : DbConstants.DB_JOIN_NOSORT)); 561 } 562 563 /// <summary> 564 /// Store multiple data items using keys from the buffer to which the 565 /// key parameter refers and data values from the buffer to which the 566 /// data parameter refers. A successful bulk operation is logically 567 /// equivalent to a loop through each key/data pair, performing a Put 568 /// for each one. 569 /// </summary> 570 /// <remarks> 571 /// 572 /// </remarks> 573 /// <param name="key">Multiple key/data pairs to store in the database 574 /// </param> Put(MultipleKeyDatabaseEntry key)575 public void Put(MultipleKeyDatabaseEntry key) { 576 Put(key, null, null); 577 } 578 579 /// <summary> 580 /// Store the key/data pair in the database, replacing any previously 581 /// existing key if duplicates are disallowed, or adding a duplicate 582 /// data item if duplicates are allowed. 583 /// </summary> 584 /// <overloads> 585 /// <para> 586 /// If the database supports duplicates, add the new data value at the 587 /// end of the duplicate set. If the database supports sorted 588 /// duplicates, the new data value is inserted at the correct sorted 589 /// location. 590 /// </para> 591 /// </overloads> 592 /// <param name="key">The key to store in the database</param> 593 /// <param name="data">The data item to store in the database</param> 594 /// <exception cref="DatabaseException"> 595 /// Partial put to a duplicate database, or <see cref="QueueDatabase"/> 596 /// or <see cref="RecnoDatabase"/> with fixed-length records. 597 /// </exception> Put(DatabaseEntry key, DatabaseEntry data)598 public void Put(DatabaseEntry key, DatabaseEntry data) { 599 Put(key, data, null); 600 } 601 602 /// <summary> 603 /// Store multiple data items using keys from the buffer to which the 604 /// key parameter refers and data values from the buffer to which the 605 /// data parameter refers. A successful bulk operation is logically 606 /// equivalent to a loop through each key/data pair, performing a Put 607 /// for each one. 608 /// </summary> 609 /// <param name="key">Multiple key/data pairs to store in the database 610 /// </param> 611 /// <param name="txn"> 612 /// If the operation is part of an application-specified transaction, 613 /// <paramref name="txn"/> is a Transaction object returned from 614 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 615 /// the operation is part of a Berkeley DB Concurrent Data Store group, 616 /// <paramref name="txn"/> is a handle returned from 617 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 618 /// </param> Put(MultipleKeyDatabaseEntry key, Transaction txn)619 public void Put(MultipleKeyDatabaseEntry key, Transaction txn) { 620 Put(key, null, txn, 0); 621 } 622 623 /// <summary> 624 /// Store the key/data pair in the database, replacing any previously 625 /// existing key if duplicates are disallowed, or adding a duplicate 626 /// data item if duplicates are allowed. 627 /// </summary> 628 /// <remarks> 629 /// <para> 630 /// When partial put to a duplicate database, a 631 /// <see cref="DatabaseException"/> is thrown. 632 /// </para> 633 /// </remarks> 634 /// <param name="key">The key to store in the database</param> 635 /// <param name="data">The data item to store in the database</param> 636 /// <param name="txn"> 637 /// If the operation is part of an application-specified transaction, 638 /// <paramref name="txn"/> is a Transaction object returned from 639 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 640 /// the operation is part of a Berkeley DB Concurrent Data Store group, 641 /// <paramref name="txn"/> is a handle returned from 642 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 643 /// </param> 644 /// <exception cref="DatabaseException"> 645 /// Partial put to a duplicate database, or <see cref="QueueDatabase"/> 646 /// or <see cref="RecnoDatabase"/> with fixed-length records. 647 /// </exception> Put( DatabaseEntry key, DatabaseEntry data, Transaction txn)648 public void Put( 649 DatabaseEntry key, DatabaseEntry data, Transaction txn) { 650 Put(key, data, txn, 0); 651 } 652 653 /// <summary> 654 /// Store the key/data pairs in the database, only if the key does not 655 /// already appear in the database. 656 /// </summary> 657 /// <param name="key">Key/data pairs to store in the database</param> PutNoOverwrite(MultipleKeyDatabaseEntry key)658 public void PutNoOverwrite(MultipleKeyDatabaseEntry key) { 659 PutNoOverwrite(key, null, null); 660 } 661 662 /// <summary> 663 /// Store the key/data pair in the database, only if the key does not 664 /// already appear in the database. 665 /// </summary> 666 /// <remarks> 667 /// This enforcement of uniqueness of keys applies only to the primary 668 /// key, the behavior of insertions into secondary databases is not 669 /// affected. In particular, the insertion of a record that would result 670 /// in the creation of a duplicate key in a secondary database that 671 /// allows duplicates would not be prevented by the use of this flag. 672 /// </remarks> 673 /// <param name="key">The key to store in the database</param> 674 /// <param name="data">The data item to store in the database</param> PutNoOverwrite(DatabaseEntry key, DatabaseEntry data)675 public void PutNoOverwrite(DatabaseEntry key, DatabaseEntry data) { 676 PutNoOverwrite(key, data, null); 677 } 678 679 /// <summary> 680 /// Store the key/data pairs in the database, only if the key does not 681 /// already appear in the database. 682 /// </summary> 683 /// <param name="key">Key/data pairs to store in the database</param> 684 /// <param name="txn"> 685 /// If the operation is part of an application-specified transaction, 686 /// <paramref name="txn"/> is a Transaction object returned from 687 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 688 /// the operation is part of a Berkeley DB Concurrent Data Store group, 689 /// <paramref name="txn"/> is a handle returned from 690 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 691 /// </param> PutNoOverwrite( MultipleKeyDatabaseEntry key, Transaction txn)692 public void PutNoOverwrite( 693 MultipleKeyDatabaseEntry key, Transaction txn) { 694 Put(key, null, txn, DbConstants.DB_NOOVERWRITE); 695 } 696 697 /// <summary> 698 /// Store the key/data pair in the database, only if the key does not 699 /// already appear in the database. 700 /// </summary> 701 /// <remarks> 702 /// This enforcement of uniqueness of keys applies only to the primary 703 /// key, the behavior of insertions into secondary databases is not 704 /// affected. In particular, the insertion of a record that would result 705 /// in the creation of a duplicate key in a secondary database that 706 /// allows duplicates would not be prevented by the use of this flag. 707 /// </remarks> 708 /// <param name="key">The key to store in the database</param> 709 /// <param name="data">The data item to store in the database</param> 710 /// <param name="txn"> 711 /// If the operation is part of an application-specified transaction, 712 /// <paramref name="txn"/> is a Transaction object returned from 713 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 714 /// the operation is part of a Berkeley DB Concurrent Data Store group, 715 /// <paramref name="txn"/> is a handle returned from 716 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 717 /// </param> PutNoOverwrite( DatabaseEntry key, DatabaseEntry data, Transaction txn)718 public void PutNoOverwrite( 719 DatabaseEntry key, DatabaseEntry data, Transaction txn) { 720 Put(key, data, txn, DbConstants.DB_NOOVERWRITE); 721 } 722 723 /// <summary> 724 /// Protected wrapper for DB->put. Used by subclasses for access method 725 /// specific operations. 726 /// </summary> 727 /// <param name="key">The key to store in the database</param> 728 /// <param name="data">The data item to store in the database</param> 729 /// <param name="txn">Transaction with which to protect the put</param> 730 /// <param name="flags">Flags to pass to DB->put</param> Put(DatabaseEntry key, DatabaseEntry data, Transaction txn, uint flags)731 protected void Put(DatabaseEntry key, 732 DatabaseEntry data, Transaction txn, uint flags) { 733 System.Type type = key.GetType(); 734 if (type == typeof(MultipleDatabaseEntry)) 735 flags |= DbConstants.DB_MULTIPLE; 736 else if (type == typeof(MultipleKeyDatabaseEntry)) 737 flags |= DbConstants.DB_MULTIPLE_KEY; 738 db.put(Transaction.getDB_TXN(txn), key, data, flags); 739 } 740 741 /// <summary> 742 /// Write the key/data pairs from all databases in the file to 743 /// <see cref="Console.Out"/>. Key values are written for Btree, Hash 744 /// and Queue databases, but not for Recno databases. 745 /// </summary> 746 /// <param name="file"> 747 /// The physical file in which the databases to be salvaged are found. 748 /// </param> 749 /// <param name="cfg"> 750 /// Configuration parameters for the databases to be salvaged. 751 /// </param> Salvage(string file, DatabaseConfig cfg)752 public static void Salvage(string file, DatabaseConfig cfg) { 753 Salvage(file, cfg, false, false, null); 754 } 755 /// <summary> 756 /// Write the key/data pairs from all databases in the file to 757 /// <see cref="Console.Out"/>. Key values are written for Btree, Hash 758 /// and Queue databases, but not for Recno databases. 759 /// </summary> 760 /// <param name="file"> 761 /// The physical file in which the databases to be salvaged are found. 762 /// </param> 763 /// <param name="cfg"> 764 /// Configuration parameters for the databases to be salvaged. 765 /// </param> 766 /// <param name="Printable"> 767 /// If true and characters in either the key or data items are printing 768 /// characters (as defined by isprint(3)), use printing characters to 769 /// represent them. This setting permits users to use standard text 770 /// editors and tools to modify the contents of databases or selectively 771 /// remove data from salvager output. 772 /// </param> Salvage( string file, DatabaseConfig cfg, bool Printable)773 public static void Salvage( 774 string file, DatabaseConfig cfg, bool Printable) { 775 Salvage(file, cfg, Printable, false, null); 776 } 777 /// <summary> 778 /// Write the key/data pairs from all databases in the file to 779 /// <paramref name="OutputStream"/>. Key values are written for Btree, 780 /// Hash and Queue databases, but not for Recno databases. 781 /// </summary> 782 /// <param name="file"> 783 /// The physical file in which the databases to be salvaged are found. 784 /// </param> 785 /// <param name="cfg"> 786 /// Configuration parameters for the databases to be salvaged. 787 /// </param> 788 /// <param name="OutputStream"> 789 /// The TextWriter to which the databases' key/data pairs are written. 790 /// If null, <see cref="Console.Out"/> will be used. 791 /// </param> Salvage( string file, DatabaseConfig cfg, TextWriter OutputStream)792 public static void Salvage( 793 string file, DatabaseConfig cfg, TextWriter OutputStream) { 794 Salvage(file, cfg, false, false, OutputStream); 795 } 796 /// <summary> 797 /// Write the key/data pairs from all databases in the file to 798 /// <paramref name="OutputStream"/>. Key values are written for Btree, 799 /// Hash and Queue databases, but not for Recno databases. 800 /// </summary> 801 /// <param name="file"> 802 /// The physical file in which the databases to be salvaged are found. 803 /// </param> 804 /// <param name="cfg"> 805 /// Configuration parameters for the databases to be salvaged. 806 /// </param> 807 /// <param name="Printable"> 808 /// If true and characters in either the key or data items are printing 809 /// characters (as defined by isprint(3)), use printing characters to 810 /// represent them. This setting permits users to use standard text 811 /// editors and tools to modify the contents of databases or selectively 812 /// remove data from salvager output. 813 /// </param> 814 /// <param name="OutputStream"> 815 /// The TextWriter to which the databases' key/data pairs are written. 816 /// If null, <see cref="Console.Out"/> will be used. 817 /// </param> Salvage(string file, DatabaseConfig cfg, bool Printable, TextWriter OutputStream)818 public static void Salvage(string file, 819 DatabaseConfig cfg, bool Printable, TextWriter OutputStream) { 820 Salvage(file, cfg, Printable, false, OutputStream); 821 } 822 /// <summary> 823 /// Write the key/data pairs from all databases in the file to 824 /// <see cref="Console.Out"/>. Key values are written for Btree, Hash 825 /// and Queue databases, but not for Recno databases. 826 /// </summary> 827 /// <param name="file"> 828 /// The physical file in which the databases to be salvaged are found. 829 /// </param> 830 /// <param name="cfg"> 831 /// Configuration parameters for the databases to be salvaged. 832 /// </param> 833 /// <param name="Printable"> 834 /// If true and characters in either the key or data items are printing 835 /// characters (as defined by isprint(3)), use printing characters to 836 /// represent them. This setting permits users to use standard text 837 /// editors and tools to modify the contents of databases or selectively 838 /// remove data from salvager output. 839 /// </param> 840 /// <param name="Aggressive"> 841 /// If true, output all the key/data pairs in the file that can be 842 /// found. Corruption will be assumed and key/data pairs that are 843 /// corrupted or have been deleted may appear in the output (even if the 844 /// file being salvaged is in no way corrupt), and the output will 845 /// almost certainly require editing before being loaded into a 846 /// database. 847 /// </param> Salvage(string file, DatabaseConfig cfg, bool Printable, bool Aggressive)848 public static void Salvage(string file, 849 DatabaseConfig cfg, bool Printable, bool Aggressive) { 850 Salvage(file, cfg, Printable, Aggressive, null); 851 } 852 /// <summary> 853 /// Write the key/data pairs from all databases in the file to 854 /// <paramref name="OutputStream"/>. Key values are written for Btree, 855 /// Hash and Queue databases, but not for Recno databases. 856 /// </summary> 857 /// <param name="file"> 858 /// The physical file in which the databases to be salvaged are found. 859 /// </param> 860 /// <param name="cfg"> 861 /// Configuration parameters for the databases to be salvaged. 862 /// </param> 863 /// <param name="Printable"> 864 /// If true and characters in either the key or data items are printing 865 /// characters (as defined by isprint(3)), use printing characters to 866 /// represent them. This setting permits users to use standard text 867 /// editors and tools to modify the contents of databases or selectively 868 /// remove data from salvager output. 869 /// </param> 870 /// <param name="Aggressive"> 871 /// If true, output all the key/data pairs in the file that can be 872 /// found. Corruption will be assumed and key/data pairs that are 873 /// corrupted or have been deleted may appear in the output (even if the 874 /// file being salvaged is in no way corrupt), and the output will 875 /// almost certainly require editing before being loaded into a 876 /// database. 877 /// </param> 878 /// <param name="OutputStream"> 879 /// The TextWriter to which the databases' key/data pairs are written. 880 /// If null, <see cref="Console.Out"/> will be used. 881 /// </param> Salvage(string file, DatabaseConfig cfg, bool Printable, bool Aggressive, TextWriter OutputStream)882 public static void Salvage(string file, DatabaseConfig cfg, 883 bool Printable, bool Aggressive, TextWriter OutputStream) { 884 using (Database db = new Database(cfg.Env, 0)) { 885 db.Config(cfg); 886 if (OutputStream == null) 887 OutputStream = Console.Out; 888 uint flags = DbConstants.DB_SALVAGE; 889 flags |= Aggressive ? DbConstants.DB_AGGRESSIVE : 0; 890 flags |= Printable ? DbConstants.DB_PRINTABLE : 0; 891 writeToFileRef = new BDB_FileWriteDelegate(writeToFile); 892 db.db.verify(file, null, OutputStream, writeToFileRef, flags); 893 } 894 } 895 896 /// <summary> 897 /// Upgrade all of the databases included in the file 898 /// <paramref name="file"/>, if necessary. If no upgrade is necessary, 899 /// Upgrade always returns successfully. 900 /// </summary> 901 /// <param name="file"> 902 /// The physical file containing the databases to be upgraded. 903 /// </param> 904 /// <param name="cfg"> 905 /// Configuration parameters for the databases to be upgraded. 906 /// </param> Upgrade(string file, DatabaseConfig cfg)907 public static void Upgrade(string file, DatabaseConfig cfg) { 908 Upgrade(file, cfg, false); 909 } 910 /// <summary> 911 /// Upgrade all of the databases included in the file 912 /// <paramref name="file"/>, if necessary. If no upgrade is necessary, 913 /// Upgrade always returns successfully. 914 /// </summary> 915 /// <overloads> 916 /// Database upgrades are done in place and are destructive. For 917 /// example, if pages need to be allocated and no disk space is 918 /// available, the database may be left corrupted. Backups should be 919 /// made before databases are upgraded. See Upgrading databases in the 920 /// Programmer's Reference Guide for more information. 921 /// </overloads> 922 /// <remarks> 923 /// <para> 924 /// As part of the upgrade from the Berkeley DB 3.0 release to the 3.1 925 /// release, the on-disk format of duplicate data items changed. To 926 /// correctly upgrade the format requires applications to specify 927 /// whether duplicate data items in the database are sorted or not. 928 /// Specifying <paramref name="dupSortUpgraded"/> informs Upgrade that 929 /// the duplicates are sorted; otherwise they are assumed to be 930 /// unsorted. Incorrectly specifying the value of this flag may lead to 931 /// database corruption. 932 /// </para> 933 /// <para> 934 /// Further, because this method upgrades a physical file (including all 935 /// the databases it contains), it is not possible to use Upgrade to 936 /// upgrade files in which some of the databases it includes have sorted 937 /// duplicate data items, and some of the databases it includes have 938 /// unsorted duplicate data items. If the file does not have more than a 939 /// single database, if the databases do not support duplicate data 940 /// items, or if all of the databases that support duplicate data items 941 /// support the same style of duplicates (either sorted or unsorted), 942 /// Upgrade will work correctly as long as 943 /// <paramref name="dupSortUpgraded"/> is correctly specified. 944 /// Otherwise, the file cannot be upgraded using Upgrade it must be 945 /// upgraded manually by dumping and reloading the databases. 946 /// </para> 947 /// </remarks> 948 /// <param name="file"> 949 /// The physical file containing the databases to be upgraded. 950 /// </param> 951 /// <param name="cfg"> 952 /// Configuration parameters for the databases to be upgraded. 953 /// </param> 954 /// <param name="dupSortUpgraded"> 955 /// If true, the duplicates in the upgraded database are sorted; 956 /// otherwise they are assumed to be unsorted. This setting is only 957 /// meaningful when upgrading databases from releases before the 958 /// Berkeley DB 3.1 release. 959 /// </param> Upgrade( string file, DatabaseConfig cfg, bool dupSortUpgraded)960 public static void Upgrade( 961 string file, DatabaseConfig cfg, bool dupSortUpgraded) { 962 Database db = new Database(cfg.Env, 0); 963 db.Config(cfg); 964 db.db.upgrade(file, dupSortUpgraded ? DbConstants.DB_DUPSORT : 0); 965 } 966 967 /// <summary> 968 /// Specifies the type of verification to perform 969 /// </summary> 970 public enum VerifyOperation { 971 /// <summary> 972 /// Perform database checks and check sort order 973 /// </summary> 974 DEFAULT, 975 /// <summary> 976 /// Perform the database checks for btree and duplicate sort order 977 /// and for hashing 978 /// </summary> 979 ORDER_CHECK_ONLY, 980 /// <summary> 981 /// Skip the database checks for btree and duplicate sort order and 982 /// for hashing. 983 /// </summary> 984 NO_ORDER_CHECK 985 }; 986 /// <summary> 987 /// Verify the integrity of all databases in the file specified by 988 /// <paramref name="file"/>. 989 /// </summary> 990 /// <overloads> 991 /// Verify does not perform any locking, even in Berkeley DB 992 /// environments that are configured with a locking subsystem. As such, 993 /// it should only be used on files that are not being modified by 994 /// another thread of control. 995 /// </overloads> 996 /// <param name="file"> 997 /// The physical file in which the databases to be verified are found. 998 /// </param> 999 /// <param name="cfg"> 1000 /// Configuration parameters for the databases to be verified. 1001 /// </param> Verify(string file, DatabaseConfig cfg)1002 public static void Verify(string file, DatabaseConfig cfg) { 1003 Verify(file, null, cfg, VerifyOperation.DEFAULT); 1004 } 1005 /// <summary> 1006 /// Verify the integrity of all databases in the file specified by 1007 /// <paramref name="file"/>. 1008 /// </summary> 1009 /// <remarks> 1010 /// <para> 1011 /// Berkeley DB normally verifies that btree keys and duplicate items 1012 /// are correctly sorted, and hash keys are correctly hashed. If the 1013 /// file being verified contains multiple databases using differing 1014 /// sorting or hashing algorithms, some of them must necessarily fail 1015 /// database verification because only one sort order or hash function 1016 /// can be specified in <paramref name="cfg"/>. To verify files with 1017 /// multiple databases having differing sorting orders or hashing 1018 /// functions, first perform verification of the file as a whole by 1019 /// using <see cref="VerifyOperation.NO_ORDER_CHECK"/>, and then 1020 /// individually verify the sort order and hashing function for each 1021 /// database in the file using 1022 /// <see cref="VerifyOperation.ORDER_CHECK_ONLY"/>. 1023 /// </para> 1024 /// </remarks> 1025 /// <param name="file"> 1026 /// The physical file in which the databases to be verified are found. 1027 /// </param> 1028 /// <param name="cfg"> 1029 /// Configuration parameters for the databases to be verified. 1030 /// </param> 1031 /// <param name="op">The extent of verification</param> Verify( string file, DatabaseConfig cfg, VerifyOperation op)1032 public static void Verify( 1033 string file, DatabaseConfig cfg, VerifyOperation op) { 1034 Verify(file, null, cfg, op); 1035 } 1036 /// <summary> 1037 /// Verify the integrity of the database specified by 1038 /// <paramref name="file"/> and <paramref name="database"/>. 1039 /// </summary> 1040 /// <remarks> 1041 /// <para> 1042 /// Berkeley DB normally verifies that btree keys and duplicate items 1043 /// are correctly sorted, and hash keys are correctly hashed. If the 1044 /// file being verified contains multiple databases using differing 1045 /// sorting or hashing algorithms, some of them must necessarily fail 1046 /// database verification because only one sort order or hash function 1047 /// can be specified in <paramref name="cfg"/>. To verify files with 1048 /// multiple databases having differing sorting orders or hashing 1049 /// functions, first perform verification of the file as a whole by 1050 /// using <see cref="VerifyOperation.NO_ORDER_CHECK"/>, and then 1051 /// individually verify the sort order and hashing function for each 1052 /// database in the file using 1053 /// <see cref="VerifyOperation.ORDER_CHECK_ONLY"/>. 1054 /// </para> 1055 /// </remarks> 1056 /// <param name="file"> 1057 /// The physical file in which the databases to be verified are found. 1058 /// </param> 1059 /// <param name="database"> 1060 /// The database in <paramref name="file"/> on which the database checks 1061 /// for btree and duplicate sort order and for hashing are to be 1062 /// performed. A non-null value for database is only allowed with 1063 /// <see cref="VerifyOperation.ORDER_CHECK_ONLY"/>. 1064 /// </param> 1065 /// <param name="cfg"> 1066 /// Configuration parameters for the databases to be verified. 1067 /// </param> 1068 /// <param name="op">The extent of verification</param> Verify(string file, string database, DatabaseConfig cfg, VerifyOperation op)1069 public static void Verify(string file, 1070 string database, DatabaseConfig cfg, VerifyOperation op) { 1071 using (Database db = new Database(cfg.Env, 0)) { 1072 db.Config(cfg); 1073 uint flags; 1074 switch (op) { 1075 case VerifyOperation.NO_ORDER_CHECK: 1076 flags = DbConstants.DB_NOORDERCHK; 1077 break; 1078 case VerifyOperation.ORDER_CHECK_ONLY: 1079 flags = DbConstants.DB_ORDERCHKONLY; 1080 break; 1081 case VerifyOperation.DEFAULT: 1082 default: 1083 flags = 0; 1084 break; 1085 } 1086 db.db.verify(file, database, null, null, flags); 1087 } 1088 } 1089 #endregion Methods 1090 } 1091 } 1092