1 /*- 2 * Copyright (c) 2009, 2020 Oracle and/or its affiliates. All rights reserved. 3 * 4 * See the file LICENSE for license information. 5 * 6 */ 7 using System; 8 using System.Collections.Generic; 9 using System.Text; 10 11 using BerkeleyDB.Internal; 12 13 namespace BerkeleyDB { 14 /// <summary> 15 /// A class representing configuration parameters for 16 /// <see cref="BTreeDatabase"/> 17 /// </summary> 18 public class BTreeDatabaseConfig : DatabaseConfig { 19 /* Fields for DB->set_flags() */ 20 /// <summary> 21 /// Policy for duplicate data items in the database. Allows a key/data 22 /// pair to be inserted into the database even if the key already exists. 23 /// </summary> 24 /// <remarks> 25 /// <para>The ordering of duplicates in the database for 26 /// <see cref="DuplicatesPolicy.UNSORTED"/> is determined by the order 27 /// of insertion, unless the ordering is otherwise specified by use of a 28 /// cursor operation or a duplicate sort function. The ordering of 29 /// duplicates in the database for 30 /// <see cref="DuplicatesPolicy.SORTED"/> is determined by the 31 /// duplicate comparison function. If the application does not specify a 32 /// comparison function using 33 /// <see cref="DuplicateCompare"/>, a default lexical 34 /// comparison is used. 35 /// </para> 36 /// <para> 37 /// <see cref="DuplicatesPolicy.SORTED"/> is preferred to 38 /// <see cref="DuplicatesPolicy.UNSORTED"/> for performance reasons. 39 /// <see cref="DuplicatesPolicy.UNSORTED"/> should only be used by 40 /// applications wanting to order duplicate data items manually. 41 /// </para> 42 /// <para> 43 /// If the database already exists, the value of Duplicates must be the 44 /// same as the existing database or an error is returned. 45 /// </para> 46 /// <para> 47 /// It is an error to specify <see cref="UseRecordNumbers"/> and 48 /// anything other than <see cref="DuplicatesPolicy.NONE"/>. 49 /// </para> 50 /// </remarks> 51 public DuplicatesPolicy Duplicates; 52 /// <summary> 53 /// Turn reverse splitting in the Btree on or off. 54 /// </summary> 55 /// <remarks> 56 /// As pages are emptied in a database, the Berkeley DB Btree 57 /// implementation attempts to coalesce empty pages into higher-level 58 /// pages in order to keep the database as small as possible and 59 /// minimize search time. This can hurt performance in applications with 60 /// cyclical data demands; applications where the database 61 /// grows and shrinks repeatedly. For example, because Berkeley DB does 62 /// page-level locking, the maximum level of concurrency in a database 63 /// of two pages is far smaller than that in a database of 100 pages, so 64 /// a database that has shrunk to a minimal size can cause severe 65 /// deadlocking when a new cycle of data insertion begins. 66 /// </remarks> 67 public bool NoReverseSplitting; 68 /// <summary> 69 /// If true, support retrieval from the Btree using record numbers. 70 /// </summary> 71 /// <remarks> 72 /// <para> 73 /// Logical record numbers in Btree databases are mutable in the face of 74 /// record insertion or deletion. See 75 /// <see cref="RecnoDatabaseConfig.Renumber"/> for further discussion. 76 /// </para> 77 /// <para> 78 /// Maintaining record counts within a Btree introduces a serious point 79 /// of contention, namely the page locations where the record counts are 80 /// stored. In addition, the entire database must be locked during both 81 /// insertions and deletions, effectively single-threading the database 82 /// for those operations. Specifying UseRecordNumbers can result in 83 /// serious performance degradation for some applications and data sets. 84 /// </para> 85 /// <para> 86 /// It is an error to specify <see cref="UseRecordNumbers"/> and 87 /// anything other than <see cref="DuplicatesPolicy.NONE"/>. 88 /// </para> 89 /// <para> 90 /// If the database already exists, the value of UseRecordNumbers must 91 /// be the same as the existing database or an error is returned. 92 /// </para> 93 /// </remarks> 94 public bool UseRecordNumbers; 95 internal new uint flags { 96 get { 97 uint ret = base.flags; 98 ret |= (uint)Duplicates; 99 ret |= NoReverseSplitting ? 100 Internal.DbConstants.DB_REVSPLITOFF : 0; 101 ret |= UseRecordNumbers ? Internal.DbConstants.DB_RECNUM : 0; 102 return ret; 103 } 104 } 105 /// <summary> 106 /// The path of the directory where external files are stored. 107 /// <para> 108 /// If the database is opened within <see cref="DatabaseEnvironment"/>, 109 /// this path setting is ignored during 110 /// <see cref="BTreeDatabase.Open"/>. Use 111 /// <see cref="BTreeDatabase.ExternalFileDir"/> to identify the current 112 /// storage location of external files after opening the database. 113 /// </para> 114 /// <para> 115 /// Replaces BlobDir. 116 /// </para> 117 /// </summary> 118 public string ExternalFileDir; 119 /// <summary> 120 /// Deprecated. Replaced by ExternalFileDir. 121 /// </summary> 122 public string BlobDir; 123 124 internal bool blobThresholdIsSet; 125 private uint blobThreshold; 126 /// <summary> 127 /// Deprecated. Replaced by ExternalFileThreshold. 128 /// </summary> 129 public uint BlobThreshold { 130 get { return blobThreshold; } 131 set { 132 blobThresholdIsSet = true; 133 blobThreshold = value; 134 } 135 } 136 /// <summary> 137 /// The size in bytes which is used to determine when a data item 138 /// is stored as an external file. 139 /// <para> 140 /// Any data item that is equal to or larger in size than the 141 /// threshold value is automatically stored as an external file. 142 /// </para> 143 /// <para> 144 /// If the threshold value is 0, external files are never be used by the 145 /// database. 146 /// </para> 147 /// <para> 148 /// It is illegal to enable external file support in the database which 149 /// is configured as in-memory database or with duplicates, 150 /// sorted duplicates, compression, multiversion concurrency control 151 /// and transactional read operations with degree 1 isolation. 152 /// </para> 153 /// </summary> 154 public uint ExternalFileThreshold { 155 get { return blobThreshold; } 156 set { 157 blobThresholdIsSet = true; 158 blobThreshold = value; 159 } 160 } 161 162 /// <summary> 163 /// The policy for how to handle database creation. 164 /// </summary> 165 /// <remarks> 166 /// If the database does not already exist and 167 /// <see cref="CreatePolicy.NEVER"/> is set, 168 /// <see cref="BTreeDatabase.Open"/> fails. 169 /// </remarks> 170 public CreatePolicy Creation; 171 internal new uint openFlags { 172 get { 173 uint flags = base.openFlags; 174 flags |= (uint)Creation; 175 return flags; 176 } 177 } 178 179 /// <summary> 180 /// The Btree key comparison function. 181 /// </summary> 182 /// <remarks> 183 /// <para> 184 /// The comparison function is called whenever it is necessary to 185 /// compare a key specified by the application with a key currently 186 /// stored in the tree. 187 /// </para> 188 /// <para> 189 /// If no comparison function is specified, the keys are compared 190 /// lexically, with shorter keys collating before longer keys. 191 /// </para> 192 /// <para> 193 /// If the database already exists, the comparison function must be the 194 /// same as that historically used to create the database or corruption 195 /// can occur. 196 /// </para> 197 /// </remarks> 198 public EntryComparisonDelegate BTreeCompare; 199 /// <summary> 200 /// The Btree prefix function. 201 /// </summary> 202 /// <remarks> 203 /// <para> 204 /// The prefix function is used to determine the amount by which keys 205 /// stored on the Btree internal pages can be safely truncated without 206 /// losing their uniqueness. See the Btree prefix comparison section of 207 /// the Berkeley DB Reference Guide for more details about how this 208 /// works. The usefulness of this is data-dependent, but can produce 209 /// significantly reduced tree sizes and search times in some data sets. 210 /// </para> 211 /// <para> 212 /// If no prefix function or key comparison function is specified by the 213 /// application, a default lexical comparison function is used as the 214 /// prefix function. If no prefix function is specified and 215 /// <see cref="BTreeCompare"/> is specified, no prefix function is 216 /// used. It is an error to specify a prefix function without also 217 /// specifying <see cref="BTreeCompare"/>. 218 /// </para> 219 /// <para> 220 /// If the database already exists, the prefix function must be the 221 /// same as that historically used to create the database or corruption 222 /// can occur. 223 /// </para> 224 /// </remarks> 225 public EntryPrefixComparisonDelegate BTreePrefixCompare; 226 /// <summary> 227 /// The duplicate data item comparison function. 228 /// </summary> 229 /// <remarks> 230 /// <para> 231 /// The comparison function is called whenever it is necessary to 232 /// compare a data item specified by the application with a data item 233 /// currently stored in the database. Setting DuplicateCompare implies 234 /// setting <see cref="Duplicates"/> to 235 /// <see cref="DuplicatesPolicy.SORTED"/>. 236 /// </para> 237 /// <para> 238 /// If no comparison function is specified, the data items are compared 239 /// lexically, with shorter data items collating before longer data 240 /// items. 241 /// </para> 242 /// <para> 243 /// If the database already exists when 244 /// <see cref="BTreeDatabase.Open"/> is called, the 245 /// delegate must be the same as that historically used to create the 246 /// database or corruption can occur. 247 /// </para> 248 /// </remarks> 249 public EntryComparisonDelegate DuplicateCompare; 250 251 internal bool compressionIsSet; 252 private BTreeCompressDelegate compressFunc; 253 /// <summary> 254 /// The compression function used to store key/data pairs in the 255 /// database. 256 /// </summary> 257 public BTreeCompressDelegate Compress { get { return compressFunc; } } 258 private BTreeDecompressDelegate decompressFunc; 259 /// <summary> 260 /// The decompression function used to retrieve key/data pairs from the 261 /// database. 262 /// </summary> 263 public BTreeDecompressDelegate Decompress { 264 get { return decompressFunc; } 265 } 266 /// <summary> 267 /// Enable compression of the key/data pairs stored in the database, 268 /// using the default compression and decompression functions. 269 /// </summary> 270 /// <remarks> 271 /// The default functions perform prefix compression on keys, and prefix 272 /// compression on data items for duplicate keys. 273 /// </remarks> SetCompression()274 public void SetCompression() { 275 compressionIsSet = true; 276 compressFunc = null; 277 decompressFunc = null; 278 } 279 /// <summary> 280 /// Enable compression of the key/data pairs stored in the database, 281 /// using the specified compression and decompression functions. 282 /// </summary> 283 /// <param name="compression">The compression function</param> 284 /// <param name="decompression">The decompression function</param> SetCompression(BTreeCompressDelegate compression, BTreeDecompressDelegate decompression)285 public void SetCompression(BTreeCompressDelegate compression, 286 BTreeDecompressDelegate decompression) { 287 compressionIsSet = true; 288 compressFunc = compression; 289 decompressFunc = decompression; 290 } 291 292 internal bool minkeysIsSet; 293 private uint minKeys; 294 /// <summary> 295 /// The minimum number of key/data pairs intended to be stored on any 296 /// single Btree leaf page. 297 /// </summary> 298 /// <remarks> 299 /// <para> 300 /// This value is used to determine if key or data items are stored 301 /// on overflow pages instead of Btree leaf pages. For more information 302 /// on the specific algorithm used, see the Berkeley DB Reference Guide. 303 /// The value specified must be at least 2; if not explicitly set, a 304 /// value of 2 is used. 305 /// </para> 306 /// <para> 307 /// If the database already exists, MinKeysPerPage is ignored. 308 /// </para> 309 /// </remarks> 310 public uint MinKeysPerPage { 311 get { return minKeys; } 312 set { 313 minkeysIsSet = true; 314 minKeys = value; 315 } 316 } 317 318 internal bool partitionIsSet; 319 private PartitionDelegate partitionFunc; 320 /// <summary> 321 /// Return the application-specified partitioning function. 322 /// </summary> 323 public PartitionDelegate Partition { get { return partitionFunc; } } 324 private DatabaseEntry[] partitionKeys; 325 /// <summary> 326 /// Return an array of type DatabaseEntry where each array entry 327 /// contains the range of keys contained in one of the database's 328 /// partitions. The array contains the information for the entire 329 /// database. 330 /// </summary> 331 public DatabaseEntry[] PartitionKeys { get { return partitionKeys; } } 332 private uint nparts; 333 /// <summary> 334 /// Return the number of partitions to create. 335 /// </summary> 336 public uint NParts { get { return nparts; } } SetPartition(uint parts, DatabaseEntry[] partKeys, PartitionDelegate partFunc)337 private bool SetPartition(uint parts, DatabaseEntry[] partKeys, 338 PartitionDelegate partFunc) { 339 partitionIsSet = true; 340 nparts = parts; 341 partitionKeys = partKeys; 342 partitionFunc = partFunc; 343 if (nparts < 2) 344 partitionIsSet = false; 345 else if (partitionKeys == null && partitionFunc == null) 346 partitionIsSet = false; 347 return partitionIsSet; 348 } 349 /// <summary> 350 /// Enable database partitioning using the specified partition keys. 351 /// Return true if partitioning is successfully enabled; otherwise 352 /// return false. 353 /// <param name="keys"> 354 /// An array of DatabaseEntry where each array entry defines the range 355 /// of key values to be stored in each partition 356 /// </param> 357 /// </summary> SetPartitionByKeys(DatabaseEntry[] keys)358 public bool SetPartitionByKeys(DatabaseEntry[] keys) { 359 uint parts = (keys == null ? 0 : ((uint)keys.Length + 1)); 360 return (SetPartition(parts, keys, null)); 361 } 362 /// <summary> 363 /// Enable database partitioning using the specified number of 364 /// partitions and partition function. 365 /// Return true if the specified number of partitions are successfully 366 /// enabled; otherwise return false. 367 /// <param name="parts">The number of partitions to create</param> 368 /// <param name="partFunc">The name of partitioning function</param> 369 /// </summary> SetPartitionByCallback( uint parts, PartitionDelegate partFunc)370 public bool SetPartitionByCallback( 371 uint parts, PartitionDelegate partFunc) { 372 return (SetPartition(parts, null, partFunc)); 373 } 374 375 /// <summary> 376 /// Create a new BTreeDatabaseConfig object 377 /// </summary> BTreeDatabaseConfig()378 public BTreeDatabaseConfig() { 379 Duplicates = DuplicatesPolicy.NONE; 380 NoReverseSplitting = false; 381 UseRecordNumbers = false; 382 383 blobThresholdIsSet = false; 384 385 BTreeCompare = null; 386 BTreePrefixCompare = null; 387 388 minkeysIsSet = false; 389 390 Creation = CreatePolicy.NEVER; 391 } 392 } 393 } 394