/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2009 Oracle. All rights reserved.
*
*/
using System;
using System.Collections.Generic;
using System.Text;
using BerkeleyDB.Internal;
namespace BerkeleyDB {
///
/// A class that provides an arbitrary number of persistent objects that
/// return an increasing or decreasing sequence of integers.
///
public class Sequence : IDisposable {
private DB_SEQUENCE seq;
private bool isOpen;
///
/// Instantiate a new Sequence object.
///
///
/// If is null and the operation occurs in a
/// transactional database, the operation will be implicitly transaction
/// protected.
///
/// Configuration parameters for the Sequence
public Sequence(SequenceConfig cfg) : this(cfg, null) { }
///
/// Instantiate a new Sequence object.
///
///
/// If is null and the operation occurs in a
/// transactional database, the operation will be implicitly transaction
/// protected.
///
/// Configuration parameters for the Sequence
///
/// If the operation is part of an application-specified transaction,
/// is a Transaction object returned from
/// ; if
/// the operation is part of a Berkeley DB Concurrent Data Store group,
/// is a handle returned from
/// ; otherwise null.
///
public Sequence(SequenceConfig cfg, Transaction txn) {
seq = new DB_SEQUENCE(cfg.BackingDatabase.db, 0);
if (cfg.initialValIsSet)
seq.initial_value(cfg.InitialValue);
seq.set_flags(cfg.flags);
if (cfg.rangeIsSet)
seq.set_range(cfg.Min, cfg.Max);
if (cfg.cacheSzIsSet)
seq.set_cachesize(cfg.CacheSize);
seq.open(Transaction.getDB_TXN(txn),
cfg.key, cfg.openFlags);
isOpen = true;
}
///
/// Close the sequence handle. Any unused cached values are lost.
///
public void Close() {
isOpen = false;
seq.close(0);
}
///
/// Return the next available element in the sequence and change the
/// sequence value by .
///
///
///
/// If there are enough cached values in the sequence handle then they
/// will be returned. Otherwise the next value will be fetched from the
/// database and incremented (decremented) by enough to cover the delta
/// and the next batch of cached values.
///
///
/// For maximum concurrency a non-zero cache size should be specified
/// prior to opening the sequence handle and
/// should be specified for each Get method call.
///
///
/// By default, sequence ranges do not wrap; to cause the sequence to
/// wrap around the beginning or end of its range, set
/// to true.
///
///
/// If was opened in a transaction,
/// calling Get may result in changes to the sequence object; these
/// changes will be automatically committed in a transaction internal to
/// the Berkeley DB library. If the thread of control calling Get has an
/// active transaction, which holds locks on the same database as the
/// one in which the sequence object is stored, it is possible for a
/// thread of control calling Get to self-deadlock because the active
/// transaction's locks conflict with the internal transaction's locks.
/// For this reason, it is often preferable for sequence objects to be
/// stored in their own database.
///
///
///
/// The amount by which to increment the sequence value. Must be
/// greater than 0.
///
/// The next available element in the sequence.
public Int64 Get(int Delta) {
return Get(Delta, false, null);
}
///
/// Return the next available element in the sequence and change the
/// sequence value by .
///
///
/// The amount by which to increment the sequence value. Must be
/// greater than 0.
///
///
/// If true, and if the operation is implicitly transaction protected,
/// do not synchronously flush the log when the transaction commits.
///
/// The next available element in the sequence.
public Int64 Get(int Delta, bool NoSync) {
return Get(Delta, NoSync, null);
}
///
/// Return the next available element in the sequence and change the
/// sequence value by .
///
///
/// The amount by which to increment the sequence value. Must be
/// greater than 0.
///
///
/// If the operation is part of an application-specified transaction,
/// is a Transaction object returned from
/// ; if
/// the operation is part of a Berkeley DB Concurrent Data Store group,
/// is a handle returned from
/// ; otherwise null.
/// Must be null if the sequence was opened with a non-zero cache size.
///
/// The next available element in the sequence.
public Int64 Get(int Delta, Transaction txn) {
return Get(Delta, false, txn);
}
private Int64 Get(int Delta, bool NoSync, Transaction txn) {
Int64 ret = DbConstants.DB_AUTO_COMMIT;
uint flags = NoSync ? DbConstants.DB_TXN_NOSYNC : 0;
seq.get(Transaction.getDB_TXN(txn), Delta, ref ret, flags);
return ret;
}
///
/// The database used by the sequence.
///
public Database BackingDatabase {
get { return Database.fromDB(seq.get_db()); }
}
///
/// The key for the sequence.
///
public DatabaseEntry Key {
get {
DatabaseEntry ret = new DatabaseEntry();
seq.get_key(ret);
return ret;
}
}
///
/// Print diagnostic information.
///
public void PrintStats() {
PrintStats(false);
}
///
/// Print diagnostic information.
///
///
/// The diagnostic information is described by
/// .
///
///
/// If true, reset statistics after printing.
///
public void PrintStats(bool ClearStats) {
uint flags = 0;
flags |= ClearStats ? DbConstants.DB_STAT_CLEAR : 0;
seq.stat_print(flags);
}
///
/// Remove the sequence from the database.
///
public void Remove() {
Remove(false, null);
}
///
/// Remove the sequence from the database.
///
///
/// If true, and if the operation is implicitly transaction protected,
/// do not synchronously flush the log when the transaction commits.
///
public void Remove(bool NoSync) {
Remove(NoSync, null);
}
///
/// Remove the sequence from the database.
///
///
/// If the operation is part of an application-specified transaction,
/// is a Transaction object returned from
/// ; if
/// the operation is part of a Berkeley DB Concurrent Data Store group,
/// is a handle returned from
/// ; otherwise null.
///
public void Remove(Transaction txn) {
Remove(false, txn);
}
private void Remove(bool NoSync, Transaction txn) {
uint flags = NoSync ? DbConstants.DB_TXN_NOSYNC : 0;
isOpen = false;
seq.remove(Transaction.getDB_TXN(txn), flags);
}
///
/// Return statistical information for this sequence.
///
/// Statistical information for this sequence.
public SequenceStats Stats() {
return Stats(false);
}
///
/// Return statistical information for this sequence.
///
///
///
/// In the presence of multiple threads or processes accessing an active
/// sequence, the information returned by DB_SEQUENCE->stat() may be
/// out-of-date.
///
///
/// The DB_SEQUENCE->stat() method cannot be transaction-protected. For
/// this reason, it should be called in a thread of control that has no
/// open cursors or active transactions.
///
///
/// If true, reset statistics.
/// Statistical information for this sequence.
public SequenceStats Stats(bool clear) {
uint flags = 0;
flags |= clear ? DbConstants.DB_STAT_CLEAR : 0;
SequenceStatStruct st = seq.stat(flags);
return new SequenceStats(st);
}
///
/// Release the resources held by this object, and close the sequence if
/// it's still open.
///
public void Dispose() {
if (isOpen)
seq.close(0);
seq.Dispose();
GC.SuppressFinalize(this);
}
///
/// The current cache size.
///
public int Cachesize {
get {
int ret = 0;
seq.get_cachesize(ref ret);
return ret;
}
}
///
/// The minimum value in the sequence.
///
public Int64 Min {
get {
Int64 ret = 0;
Int64 tmp = 0;
seq.get_range(ref ret, ref tmp);
return ret;
}
}
///
/// The maximum value in the sequence.
///
public Int64 Max {
get {
Int64 ret = 0;
Int64 tmp = 0;
seq.get_range(ref tmp, ref ret);
return ret;
}
}
///
/// If true, the sequence should wrap around when it is incremented
/// (decremented) past the specified maximum (minimum) value.
///
public bool Wrap {
get {
uint flags = 0;
seq.get_flags(ref flags);
return (flags & DbConstants.DB_SEQ_WRAP) != 0;
}
}
///
/// If true, the sequence will be incremented. This is the default.
///
public bool Increment {
get {
uint flags = 0;
seq.get_flags(ref flags);
return (flags & DbConstants.DB_SEQ_INC) != 0;
}
}
///
/// If true, the sequence will be decremented.
///
public bool Decrement {
get {
uint flags = 0;
seq.get_flags(ref flags);
return (flags & DbConstants.DB_SEQ_DEC) != 0;
}
}
}
}