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