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.Runtime.InteropServices; 10 using System.Text; 11 using BerkeleyDB.Internal; 12 13 namespace BerkeleyDB { 14 /// <summary> 15 /// A class representing a SecondaryHashDatabase. The Hash format is an 16 /// extensible, dynamic hashing scheme. 17 /// </summary> 18 public class SecondaryHashDatabase : SecondaryDatabase { 19 private HashFunctionDelegate hashHandler; 20 private EntryComparisonDelegate compareHandler; 21 private EntryComparisonDelegate dupCompareHandler; 22 private BDB_CompareDelegate doCompareRef; 23 private BDB_HashDelegate doHashRef; 24 private BDB_CompareDelegate doDupCompareRef; 25 26 #region Constructors SecondaryHashDatabase(DatabaseEnvironment env, uint flags)27 internal SecondaryHashDatabase(DatabaseEnvironment env, uint flags) : base(env, flags) { } 28 Config(SecondaryHashDatabaseConfig cfg)29 private void Config(SecondaryHashDatabaseConfig cfg) { 30 base.Config(cfg); 31 db.set_flags(cfg.flags); 32 33 if (cfg.HashFunction != null) 34 HashFunction = cfg.HashFunction; 35 if (cfg.DuplicateCompare != null) 36 DupCompare = cfg.DuplicateCompare; 37 if (cfg.fillFactorIsSet) 38 db.set_h_ffactor(cfg.FillFactor); 39 if (cfg.nelemIsSet) 40 db.set_h_nelem(cfg.TableSize); 41 if (cfg.Compare != null) 42 Compare = cfg.Compare; 43 } 44 45 /// <summary> 46 /// Instantiate a new SecondaryHashDatabase object, open the 47 /// database represented by <paramref name="Filename"/> and associate 48 /// the database with the 49 /// <see cref="SecondaryDatabaseConfig.Primary">primary index</see>. 50 /// </summary> 51 /// <remarks> 52 /// <para> 53 /// If <paramref name="Filename"/> is null, the database is strictly 54 /// temporary and cannot be opened by any other thread of control, thus 55 /// the database can only be accessed by sharing the single database 56 /// object that created it, in circumstances where doing so is safe. 57 /// </para> 58 /// <para> 59 /// If <see cref="DatabaseConfig.AutoCommit"/> is set, the operation 60 /// will be implicitly transaction protected. Note that transactionally 61 /// protected operations on a datbase object requires the object itself 62 /// be transactionally protected during its open. 63 /// </para> 64 /// </remarks> 65 /// <param name="Filename"> 66 /// The name of an underlying file that will be used to back the 67 /// database. In-memory databases never intended to be preserved on disk 68 /// may be created by setting this parameter to null. 69 /// </param> 70 /// <param name="cfg">The database's configuration</param> 71 /// <returns>A new, open database object</returns> Open( string Filename, SecondaryHashDatabaseConfig cfg)72 public static SecondaryHashDatabase Open( 73 string Filename, SecondaryHashDatabaseConfig cfg) { 74 return Open(Filename, null, cfg, null); 75 } 76 /// <summary> 77 /// Instantiate a new SecondaryHashDatabase object, open the 78 /// database represented by <paramref name="Filename"/> and associate 79 /// the database with the 80 /// <see cref="SecondaryDatabaseConfig.Primary">primary index</see>. 81 /// </summary> 82 /// <remarks> 83 /// <para> 84 /// If both <paramref name="Filename"/> and 85 /// <paramref name="DatabaseName"/> are null, the database is strictly 86 /// temporary and cannot be opened by any other thread of control, thus 87 /// the database can only be accessed by sharing the single database 88 /// object that created it, in circumstances where doing so is safe. If 89 /// <paramref name="Filename"/> is null and 90 /// <paramref name="DatabaseName"/> is non-null, the database can be 91 /// opened by other threads of control and will be replicated to client 92 /// sites in any replication group. 93 /// </para> 94 /// <para> 95 /// If <see cref="DatabaseConfig.AutoCommit"/> is set, the operation 96 /// will be implicitly transaction protected. Note that transactionally 97 /// protected operations on a datbase object requires the object itself 98 /// be transactionally protected during its open. 99 /// </para> 100 /// </remarks> 101 /// <param name="Filename"> 102 /// The name of an underlying file that will be used to back the 103 /// database. In-memory databases never intended to be preserved on disk 104 /// may be created by setting this parameter to null. 105 /// </param> 106 /// <param name="DatabaseName"> 107 /// This parameter allows applications to have multiple databases in a 108 /// single file. Although no DatabaseName needs to be specified, it is 109 /// an error to attempt to open a second database in a file that was not 110 /// initially created using a database name. 111 /// </param> 112 /// <param name="cfg">The database's configuration</param> 113 /// <returns>A new, open database object</returns> Open(string Filename, string DatabaseName, SecondaryHashDatabaseConfig cfg)114 public static SecondaryHashDatabase Open(string Filename, 115 string DatabaseName, SecondaryHashDatabaseConfig cfg) { 116 return Open(Filename, DatabaseName, cfg, null); 117 } 118 /// <summary> 119 /// Instantiate a new SecondaryHashDatabase object, open the 120 /// database represented by <paramref name="Filename"/> and associate 121 /// the database with the 122 /// <see cref="SecondaryDatabaseConfig.Primary">primary index</see>. 123 /// </summary> 124 /// <remarks> 125 /// <para> 126 /// If <paramref name="Filename"/> is null, the database is strictly 127 /// temporary and cannot be opened by any other thread of control, thus 128 /// the database can only be accessed by sharing the single database 129 /// object that created it, in circumstances where doing so is safe. 130 /// </para> 131 /// <para> 132 /// If <paramref name="txn"/> is null, but 133 /// <see cref="DatabaseConfig.AutoCommit"/> is set, the operation will 134 /// be implicitly transaction protected. Note that transactionally 135 /// protected operations on a datbase object requires the object itself 136 /// be transactionally protected during its open. Also note that the 137 /// transaction must be committed before the object is closed. 138 /// </para> 139 /// </remarks> 140 /// <param name="Filename"> 141 /// The name of an underlying file that will be used to back the 142 /// database. In-memory databases never intended to be preserved on disk 143 /// may be created by setting this parameter to null. 144 /// </param> 145 /// <param name="cfg">The database's configuration</param> 146 /// <param name="txn"> 147 /// If the operation is part of an application-specified transaction, 148 /// <paramref name="txn"/> is a Transaction object returned from 149 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 150 /// the operation is part of a Berkeley DB Concurrent Data Store group, 151 /// <paramref name="txn"/> is a handle returned from 152 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 153 /// </param> 154 /// <returns>A new, open database object</returns> Open(string Filename, SecondaryHashDatabaseConfig cfg, Transaction txn)155 public static SecondaryHashDatabase Open(string Filename, 156 SecondaryHashDatabaseConfig cfg, Transaction txn) { 157 return Open(Filename, null, cfg, txn); 158 } 159 /// <summary> 160 /// Instantiate a new SecondaryHashDatabase object, open the 161 /// database represented by <paramref name="Filename"/> and associate 162 /// the database with the 163 /// <see cref="SecondaryDatabaseConfig.Primary">primary index</see>. 164 /// </summary> 165 /// <remarks> 166 /// <para> 167 /// If both <paramref name="Filename"/> and 168 /// <paramref name="DatabaseName"/> are null, the database is strictly 169 /// temporary and cannot be opened by any other thread of control, thus 170 /// the database can only be accessed by sharing the single database 171 /// object that created it, in circumstances where doing so is safe. If 172 /// <paramref name="Filename"/> is null and 173 /// <paramref name="DatabaseName"/> is non-null, the database can be 174 /// opened by other threads of control and will be replicated to client 175 /// sites in any replication group. 176 /// </para> 177 /// <para> 178 /// If <paramref name="txn"/> is null, but 179 /// <see cref="DatabaseConfig.AutoCommit"/> is set, the operation will 180 /// be implicitly transaction protected. Note that transactionally 181 /// protected operations on a datbase object requires the object itself 182 /// be transactionally protected during its open. Also note that the 183 /// transaction must be committed before the object is closed. 184 /// </para> 185 /// </remarks> 186 /// <param name="Filename"> 187 /// The name of an underlying file that will be used to back the 188 /// database. In-memory databases never intended to be preserved on disk 189 /// may be created by setting this parameter to null. 190 /// </param> 191 /// <param name="DatabaseName"> 192 /// This parameter allows applications to have multiple databases in a 193 /// single file. Although no DatabaseName needs to be specified, it is 194 /// an error to attempt to open a second database in a file that was not 195 /// initially created using a database name. 196 /// </param> 197 /// <param name="cfg">The database's configuration</param> 198 /// <param name="txn"> 199 /// If the operation is part of an application-specified transaction, 200 /// <paramref name="txn"/> is a Transaction object returned from 201 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 202 /// the operation is part of a Berkeley DB Concurrent Data Store group, 203 /// <paramref name="txn"/> is a handle returned from 204 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 205 /// </param> 206 /// <returns>A new, open database object</returns> Open( string Filename, string DatabaseName, SecondaryHashDatabaseConfig cfg, Transaction txn)207 public static SecondaryHashDatabase Open( 208 string Filename, string DatabaseName, 209 SecondaryHashDatabaseConfig cfg, Transaction txn) { 210 SecondaryHashDatabase ret = new SecondaryHashDatabase(cfg.Env, 0); 211 ret.Config(cfg); 212 ret.db.open(Transaction.getDB_TXN(txn), Filename, 213 DatabaseName, cfg.DbType.getDBTYPE(), cfg.openFlags, 0); 214 ret.isOpen = true; 215 216 ret.doAssocRef = 217 new BDB_AssociateDelegate(SecondaryDatabase.doAssociate); 218 cfg.Primary.db.associate(Transaction.getDB_TXN(txn), 219 ret.db, ret.doAssocRef, cfg.assocFlags); 220 221 if (cfg.ForeignKeyDatabase != null) { 222 if (cfg.OnForeignKeyDelete == ForeignKeyDeleteAction.NULLIFY) 223 ret.doNullifyRef = 224 new BDB_AssociateForeignDelegate(doNullify); 225 else 226 ret.doNullifyRef = null; 227 cfg.ForeignKeyDatabase.db.associate_foreign( 228 ret.db, ret.doNullifyRef, cfg.foreignFlags); 229 } 230 return ret; 231 } 232 233 234 #endregion Constructors 235 236 #region Callbacks doDupCompare( IntPtr dbp, IntPtr dbt1p, IntPtr dbt2p)237 private static int doDupCompare( 238 IntPtr dbp, IntPtr dbt1p, IntPtr dbt2p) { 239 DB db = new DB(dbp, false); 240 DBT dbt1 = new DBT(dbt1p, false); 241 DBT dbt2 = new DBT(dbt2p, false); 242 243 SecondaryHashDatabase tmp = (SecondaryHashDatabase)db.api_internal; 244 return tmp.DupCompare( 245 DatabaseEntry.fromDBT(dbt1), DatabaseEntry.fromDBT(dbt2)); 246 } doHash(IntPtr dbp, IntPtr datap, uint len)247 private static uint doHash(IntPtr dbp, IntPtr datap, uint len) { 248 DB db = new DB(dbp, false); 249 byte[] t_data = new byte[len]; 250 Marshal.Copy(datap, t_data, 0, (int)len); 251 252 SecondaryHashDatabase tmp = (SecondaryHashDatabase)db.api_internal; 253 return tmp.HashFunction(t_data); 254 } doCompare(IntPtr dbp, IntPtr dbtp1, IntPtr dbtp2)255 private static int doCompare(IntPtr dbp, IntPtr dbtp1, IntPtr dbtp2) { 256 DB db = new DB(dbp, false); 257 DBT dbt1 = new DBT(dbtp1, false); 258 DBT dbt2 = new DBT(dbtp2, false); 259 260 SecondaryHashDatabase tmp = (SecondaryHashDatabase)db.api_internal; 261 return tmp.Compare( 262 DatabaseEntry.fromDBT(dbt1), DatabaseEntry.fromDBT(dbt2)); 263 } 264 #endregion Callbacks 265 266 #region Properties 267 /// <summary> 268 /// The secondary Hash key comparison function. The comparison function 269 /// is called whenever it is necessary to compare a key specified by the 270 /// application with a key currently stored in the tree. 271 /// </summary> 272 public EntryComparisonDelegate Compare { 273 get { return compareHandler; } 274 private set { 275 if (value == null) 276 db.set_h_compare(null); 277 else if (compareHandler == null) { 278 if (doCompareRef == null) 279 doCompareRef = new BDB_CompareDelegate(doCompare); 280 db.set_h_compare(doCompareRef); 281 } 282 compareHandler = value; 283 } 284 } 285 /// <summary> 286 /// The duplicate data item comparison function. 287 /// </summary> 288 public EntryComparisonDelegate DupCompare { 289 get { return dupCompareHandler; } 290 private set { 291 /* Cannot be called after open. */ 292 if (value == null) 293 db.set_dup_compare(null); 294 else if (dupCompareHandler == null) { 295 if (doDupCompareRef == null) 296 doDupCompareRef = new BDB_CompareDelegate(doDupCompare); 297 db.set_dup_compare(doDupCompareRef); 298 } 299 dupCompareHandler = value; 300 } 301 } 302 /// <summary> 303 /// Whether the insertion of duplicate data items in the database is 304 /// permitted, and whether duplicates items are sorted. 305 /// </summary> 306 public DuplicatesPolicy Duplicates { 307 get { 308 uint flags = 0; 309 db.get_flags(ref flags); 310 if ((flags & DbConstants.DB_DUPSORT) != 0) 311 return DuplicatesPolicy.SORTED; 312 else if ((flags & DbConstants.DB_DUP) != 0) 313 return DuplicatesPolicy.UNSORTED; 314 else 315 return DuplicatesPolicy.NONE; 316 } 317 } 318 /// <summary> 319 /// The desired density within the hash table. 320 /// </summary> 321 public uint FillFactor { 322 get { 323 uint ret = 0; 324 db.get_h_ffactor(ref ret); 325 return ret; 326 } 327 } 328 /// <summary> 329 /// A user-defined hash function; if no hash function is specified, a 330 /// default hash function is used. 331 /// </summary> 332 public HashFunctionDelegate HashFunction { 333 get { return hashHandler; } 334 private set { 335 if (value == null) 336 db.set_h_hash(null); 337 else if (hashHandler == null) { 338 if (doHashRef == null) 339 doHashRef = new BDB_HashDelegate(doHash); 340 db.set_h_hash(doHashRef); 341 } 342 hashHandler = value; 343 } 344 } 345 /// <summary> 346 /// An estimate of the final size of the hash table. 347 /// </summary> 348 public uint TableSize { 349 get { 350 uint ret = 0; 351 db.get_h_nelem(ref ret); 352 return ret; 353 } 354 } 355 #endregion Properties 356 } 357 } 358