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.Text; 10 using BerkeleyDB.Internal; 11 12 namespace BerkeleyDB { 13 /// <summary> 14 /// A class representing a QueueDatabase. The Queue format supports fast 15 /// access to fixed-length records accessed sequentially or by logical 16 /// record number. 17 /// </summary> 18 public class QueueDatabase : Database { 19 20 #region Constructors QueueDatabase(DatabaseEnvironment env, uint flags)21 private QueueDatabase(DatabaseEnvironment env, uint flags) 22 : base(env, flags) { } QueueDatabase(BaseDatabase clone)23 internal QueueDatabase(BaseDatabase clone) : base(clone) { } 24 Config(QueueDatabaseConfig cfg)25 private void Config(QueueDatabaseConfig cfg) { 26 base.Config(cfg); 27 /* 28 * Database.Config calls set_flags, but that doesn't get the Queue 29 * specific flags. No harm in calling it again. 30 */ 31 db.set_flags(cfg.flags); 32 33 db.set_re_len(cfg.Length); 34 35 if (cfg.padIsSet) 36 db.set_re_pad(cfg.PadByte); 37 if (cfg.extentIsSet) 38 db.set_q_extentsize(cfg.ExtentSize); 39 } 40 41 /// <summary> 42 /// Instantiate a new QueueDatabase object and open the database 43 /// represented by <paramref name="Filename"/>. 44 /// </summary> 45 /// <remarks> 46 /// <para> 47 /// If <paramref name="Filename"/> is null, the database is strictly 48 /// temporary and cannot be opened by any other thread of control, thus 49 /// the database can only be accessed by sharing the single database 50 /// object that created it, in circumstances where doing so is safe. 51 /// </para> 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. In-memory databases never intended to be preserved on disk 62 /// may be created by setting this parameter to null. 63 /// </param> 64 /// <param name="cfg">The database's configuration</param> 65 /// <returns>A new, open database object</returns> Open( string Filename, QueueDatabaseConfig cfg)66 public static QueueDatabase Open( 67 string Filename, QueueDatabaseConfig cfg) { 68 return Open(Filename, cfg, null); 69 } 70 /// <summary> 71 /// Instantiate a new QueueDatabase 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 <paramref name="txn"/> is null, but 83 /// <see cref="DatabaseConfig.AutoCommit"/> is set, the operation will 84 /// be implicitly transaction protected. Note that transactionally 85 /// protected operations on a datbase object requires the object itself 86 /// be transactionally protected during its open. Also note that the 87 /// transaction must be committed before the object is closed. 88 /// </para> 89 /// </remarks> 90 /// <param name="Filename"> 91 /// The name of an underlying file that will be used to back the 92 /// database. In-memory databases never intended to be preserved on disk 93 /// may be created by setting this parameter to null. 94 /// </param> 95 /// <param name="cfg">The database's configuration</param> 96 /// <param name="txn"> 97 /// If the operation is part of an application-specified transaction, 98 /// <paramref name="txn"/> is a Transaction object returned from 99 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 100 /// the operation is part of a Berkeley DB Concurrent Data Store group, 101 /// <paramref name="txn"/> is a handle returned from 102 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 103 /// </param> 104 /// <returns>A new, open database object</returns> Open( string Filename, QueueDatabaseConfig cfg, Transaction txn)105 public static QueueDatabase Open( 106 string Filename, QueueDatabaseConfig cfg, Transaction txn) { 107 QueueDatabase ret = new QueueDatabase(cfg.Env, 0); 108 ret.Config(cfg); 109 ret.db.open(Transaction.getDB_TXN(txn), 110 Filename, null, DBTYPE.DB_QUEUE, cfg.openFlags, 0); 111 ret.isOpen = true; 112 return ret; 113 } 114 115 #endregion Constructors 116 117 #region Properties 118 /// <summary> 119 /// The size of the extents used to hold pages in a 120 /// <see cref="QueueDatabase"/>, specified as a number of pages. 121 /// </summary> 122 public uint ExtentSize { 123 get { 124 uint ret = 0; 125 db.get_q_extentsize(ref ret); 126 return ret; 127 } 128 } 129 130 /// <summary> 131 /// If true, modify the operation of <see cref="QueueDatabase.Consume"/> 132 /// to return key/data pairs in order. That is, they will always return 133 /// the key/data item from the head of the queue. 134 /// </summary> 135 public bool InOrder { 136 get { 137 uint flags = 0; 138 db.get_flags(ref flags); 139 return (flags & DbConstants.DB_INORDER) != 0; 140 } 141 } 142 143 /// <summary> 144 /// The length of records in the database. 145 /// </summary> 146 public uint Length { 147 get { 148 uint ret = 0; 149 db.get_re_len(ref ret); 150 return ret; 151 } 152 } 153 154 /// <summary> 155 /// The padding character for short, fixed-length records. 156 /// </summary> 157 public int PadByte { 158 get { 159 int ret = 0; 160 db.get_re_pad(ref ret); 161 return ret; 162 } 163 } 164 #endregion Properties 165 166 #region Methods 167 /// <summary> 168 /// Append the data item to the end of the database. 169 /// </summary> 170 /// <param name="data">The data item to store in the database</param> 171 /// <returns>The record number allocated to the record</returns> Append(DatabaseEntry data)172 public uint Append(DatabaseEntry data) { 173 return Append(data, null); 174 } 175 /// <summary> 176 /// Append the data item to the end of the database. 177 /// </summary> 178 /// <remarks> 179 /// There is a minor behavioral difference between 180 /// <see cref="RecnoDatabase.Append"/> and 181 /// <see cref="QueueDatabase.Append"/>. If a transaction enclosing an 182 /// Append operation aborts, the record number may be reallocated in a 183 /// subsequent <see cref="RecnoDatabase.Append"/> operation, but it will 184 /// not be reallocated in a subsequent 185 /// <see cref="QueueDatabase.Append"/> operation. 186 /// </remarks> 187 /// <param name="data">The data item to store in the database</param> 188 /// <param name="txn"> 189 /// If the operation is part of an application-specified transaction, 190 /// <paramref name="txn"/> is a Transaction object returned from 191 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 192 /// the operation is part of a Berkeley DB Concurrent Data Store group, 193 /// <paramref name="txn"/> is a handle returned from 194 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 195 /// </param> 196 /// <returns>The record number allocated to the record</returns> Append(DatabaseEntry data, Transaction txn)197 public uint Append(DatabaseEntry data, Transaction txn) { 198 DatabaseEntry key = new DatabaseEntry(); 199 Put(key, data, txn, DbConstants.DB_APPEND); 200 return BitConverter.ToUInt32(key.Data, 0); 201 } 202 203 /// <summary> 204 /// Return the record number and data from the available record closest 205 /// to the head of the queue, and delete the record. 206 /// </summary> 207 /// <param name="wait"> 208 /// If true and the Queue database is empty, the thread of control will 209 /// wait until there is data in the queue before returning. 210 /// </param> 211 /// <exception cref="LockNotGrantedException"> 212 /// If lock or transaction timeouts have been specified, a 213 /// <see cref="LockNotGrantedException"/> may be thrown. This failure, 214 /// by itself, does not require the enclosing transaction be aborted. 215 /// </exception> 216 /// <returns> 217 /// A <see cref="KeyValuePair{T,T}"/> whose Key 218 /// parameter is the record number and whose Value parameter is the 219 /// retrieved data. 220 /// </returns> Consume(bool wait)221 public KeyValuePair<uint, DatabaseEntry> Consume(bool wait) { 222 return Consume(wait, null, null); 223 } 224 /// <summary> 225 /// Return the record number and data from the available record closest 226 /// to the head of the queue, and delete the record. 227 /// </summary> 228 /// <param name="wait"> 229 /// If true and the Queue database is empty, the thread of control will 230 /// wait until there is data in the queue before returning. 231 /// </param> 232 /// <param name="txn"> 233 /// <paramref name="txn"/> is a Transaction object returned from 234 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 235 /// the operation is part of a Berkeley DB Concurrent Data Store group, 236 /// <paramref name="txn"/> is a handle returned from 237 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 238 /// </param> 239 /// <exception cref="LockNotGrantedException"> 240 /// If lock or transaction timeouts have been specified, a 241 /// <see cref="LockNotGrantedException"/> may be thrown. This failure, 242 /// by itself, does not require the enclosing transaction be aborted. 243 /// </exception> 244 /// <returns> 245 /// A <see cref="KeyValuePair{T,T}"/> whose Key 246 /// parameter is the record number and whose Value parameter is the 247 /// retrieved data. 248 /// </returns> Consume( bool wait, Transaction txn)249 public KeyValuePair<uint, DatabaseEntry> Consume( 250 bool wait, Transaction txn) { 251 return Consume(wait, txn, null); 252 } 253 /// <summary> 254 /// Return the record number and data from the available record closest 255 /// to the head of the queue, and delete the record. 256 /// </summary> 257 /// <param name="wait"> 258 /// If true and the Queue database is empty, the thread of control will 259 /// wait until there is data in the queue before returning. 260 /// </param> 261 /// <param name="txn"> 262 /// <paramref name="txn"/> is a Transaction object returned from 263 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 264 /// the operation is part of a Berkeley DB Concurrent Data Store group, 265 /// <paramref name="txn"/> is a handle returned from 266 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 267 /// </param> 268 /// <param name="info">The locking behavior to use.</param> 269 /// <exception cref="LockNotGrantedException"> 270 /// If lock or transaction timeouts have been specified, a 271 /// <see cref="LockNotGrantedException"/> may be thrown. This failure, 272 /// by itself, does not require the enclosing transaction be aborted. 273 /// </exception> 274 /// <returns> 275 /// A <see cref="KeyValuePair{T,T}"/> whose Key 276 /// parameter is the record number and whose Value parameter is the 277 /// retrieved data. 278 /// </returns> Consume( bool wait, Transaction txn, LockingInfo info)279 public KeyValuePair<uint, DatabaseEntry> Consume( 280 bool wait, Transaction txn, LockingInfo info) { 281 KeyValuePair<DatabaseEntry, DatabaseEntry> record; 282 283 record = Get(null, null, txn, info, 284 wait ? DbConstants.DB_CONSUME_WAIT : DbConstants.DB_CONSUME); 285 return new KeyValuePair<uint, DatabaseEntry>( 286 BitConverter.ToUInt32(record.Key.Data, 0), record.Value); 287 288 } 289 290 /// <summary> 291 /// Return the database statistical information which does not require 292 /// traversal of the database. 293 /// </summary> 294 /// <returns> 295 /// The database statistical information which does not require 296 /// traversal of the database. 297 /// </returns> FastStats()298 public QueueStats FastStats() { 299 return Stats(null, true, Isolation.DEGREE_THREE); 300 } 301 /// <summary> 302 /// Return the database statistical information which does not require 303 /// traversal of the database. 304 /// </summary> 305 /// <param name="txn"> 306 /// If the operation is part of an application-specified transaction, 307 /// <paramref name="txn"/> is a Transaction object returned from 308 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 309 /// the operation is part of a Berkeley DB Concurrent Data Store group, 310 /// <paramref name="txn"/> is a handle returned from 311 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 312 /// </param> 313 /// <returns> 314 /// The database statistical information which does not require 315 /// traversal of the database. 316 /// </returns> FastStats(Transaction txn)317 public QueueStats FastStats(Transaction txn) { 318 return Stats(txn, true, Isolation.DEGREE_THREE); 319 } 320 /// <summary> 321 /// Return the database statistical information which does not require 322 /// traversal of the database. 323 /// </summary> 324 /// <overloads> 325 /// <para> 326 /// Among other things, this method makes it possible for applications 327 /// to request key and record counts without incurring the performance 328 /// penalty of traversing the entire database. 329 /// </para> 330 /// <para> 331 /// The statistical information is described by the 332 /// <see cref="BTreeStats"/>, <see cref="HashStats"/>, 333 /// <see cref="QueueStats"/>, and <see cref="RecnoStats"/> classes. 334 /// </para> 335 /// </overloads> 336 /// <param name="txn"> 337 /// If the operation is part of an application-specified transaction, 338 /// <paramref name="txn"/> is a Transaction object returned from 339 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 340 /// the operation is part of a Berkeley DB Concurrent Data Store group, 341 /// <paramref name="txn"/> is a handle returned from 342 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 343 /// </param> 344 /// <param name="isoDegree"> 345 /// The level of isolation for database reads. 346 /// <see cref="Isolation.DEGREE_ONE"/> will be silently ignored for 347 /// databases which did not specify 348 /// <see cref="DatabaseConfig.ReadUncommitted"/>. 349 /// </param> 350 /// <returns> 351 /// The database statistical information which does not require 352 /// traversal of the database. 353 /// </returns> FastStats(Transaction txn, Isolation isoDegree)354 public QueueStats FastStats(Transaction txn, Isolation isoDegree) { 355 return Stats(txn, true, isoDegree); 356 } 357 358 /// <summary> 359 /// Return the database statistical information for this database. 360 /// </summary> 361 /// <returns>Database statistical information.</returns> Stats()362 public QueueStats Stats() { 363 return Stats(null, false, Isolation.DEGREE_THREE); 364 } 365 /// <summary> 366 /// Return the database statistical information for this database. 367 /// </summary> 368 /// <param name="txn"> 369 /// If the operation is part of an application-specified transaction, 370 /// <paramref name="txn"/> is a Transaction object returned from 371 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 372 /// the operation is part of a Berkeley DB Concurrent Data Store group, 373 /// <paramref name="txn"/> is a handle returned from 374 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 375 /// </param> 376 /// <returns>Database statistical information.</returns> Stats(Transaction txn)377 public QueueStats Stats(Transaction txn) { 378 return Stats(txn, false, Isolation.DEGREE_THREE); 379 } 380 /// <summary> 381 /// Return the database statistical information for this database. 382 /// </summary> 383 /// <overloads> 384 /// The statistical information is described by 385 /// <see cref="BTreeStats"/>. 386 /// </overloads> 387 /// <param name="txn"> 388 /// If the operation is part of an application-specified transaction, 389 /// <paramref name="txn"/> is a Transaction object returned from 390 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 391 /// the operation is part of a Berkeley DB Concurrent Data Store group, 392 /// <paramref name="txn"/> is a handle returned from 393 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 394 /// </param> 395 /// <param name="isoDegree"> 396 /// The level of isolation for database reads. 397 /// <see cref="Isolation.DEGREE_ONE"/> will be silently ignored for 398 /// databases which did not specify 399 /// <see cref="DatabaseConfig.ReadUncommitted"/>. 400 /// </param> 401 /// <returns>Database statistical information.</returns> Stats(Transaction txn, Isolation isoDegree)402 public QueueStats Stats(Transaction txn, Isolation isoDegree) { 403 return Stats(txn, false, isoDegree); 404 } Stats(Transaction txn, bool fast, Isolation isoDegree)405 private QueueStats Stats(Transaction txn, bool fast, Isolation isoDegree) { 406 uint flags = 0; 407 flags |= fast ? DbConstants.DB_FAST_STAT : 0; 408 switch (isoDegree) { 409 case Isolation.DEGREE_ONE: 410 flags |= DbConstants.DB_READ_UNCOMMITTED; 411 break; 412 case Isolation.DEGREE_TWO: 413 flags |= DbConstants.DB_READ_COMMITTED; 414 break; 415 } 416 QueueStatStruct st = db.stat_qam(Transaction.getDB_TXN(txn), flags); 417 return new QueueStats(st); 418 } 419 #endregion Methods 420 } 421 } 422