1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2009 Oracle.  All rights reserved.
5 *
6 */
7using System;
8using System.Collections.Generic;
9using System.Text;
10
11namespace BerkeleyDB {
12    /// <summary>
13    /// A class representing configuration parameters for
14    /// <see cref="RecnoDatabase"/>
15    /// </summary>
16    public class RecnoDatabaseConfig : DatabaseConfig {
17        /* Fields for DB->set_flags() */
18        /// <summary>
19        /// Cause the logical record numbers to be mutable, and change as
20        /// records are added to and deleted from the database.
21        /// </summary>
22        /// <remarks>
23        /// <para>
24        /// Using <see cref="Database.Put"/> or <see cref="Cursor.Put"/> to
25        /// create new records will cause the creation of multiple records if
26        /// the record number is more than one greater than the largest record
27        /// currently in the database. For example, creating record 28, when
28        /// record 25 was previously the last record in the database, will
29        /// create records 26 and 27 as well as 28. Attempts to retrieve records
30        /// that were created in this manner will throw a
31        /// <see cref="KeyEmptyException"/>.
32        /// </para>
33        /// <para>
34        /// If a created record is not at the end of the database, all records
35        /// following the new record will be automatically renumbered upward by
36        /// one. For example, the creation of a new record numbered 8 causes
37        /// records numbered 8 and greater to be renumbered upward by one. If a
38        /// cursor was positioned to record number 8 or greater before the
39        /// insertion, it will be shifted upward one logical record, continuing
40        /// to refer to the same record as it did before.
41        /// </para>
42        /// <para>
43        /// If a deleted record is not at the end of the database, all records
44        /// following the removed record will be automatically renumbered
45        /// downward by one. For example, deleting the record numbered 8 causes
46        /// records numbered 9 and greater to be renumbered downward by one.  If
47        /// a cursor was positioned to record number 9 or greater before the
48        /// removal, it will be shifted downward one logical record, continuing
49        /// to refer to the same record as it did before.
50        /// </para>
51        /// <para>
52        /// If a record is deleted, all cursors that were positioned on that
53        /// record prior to the removal will no longer be positioned on a valid
54        /// entry. This includes cursors used to delete an item. For example, if
55        /// a cursor was positioned to record number 8 before the removal of
56        /// that record, subsequent calls to <see cref="Cursor.Refresh"/>
57        /// will return false until the cursor is moved to another record. A
58        /// call to <see cref="Cursor.MoveNext"/> will return the new record
59        /// numbered 8 - which is the record that was numbered 9 prior to the
60        /// delete (if such a record existed).
61        /// </para>
62        /// <para>
63        /// For these reasons, concurrent access to a
64        /// <see cref="RecnoDatabase"/> with this setting specified may be
65        /// largely meaningless, although it is supported.
66        /// </para>
67        /// <para>
68        /// If the database already exists, this setting must be the same as the
69        /// existing database or an exception will be thrown.
70        /// </para>
71        /// </remarks>
72        public bool Renumber;
73        /// <summary>
74        /// If true, any <see cref="BackingFile"/> file will be read in its
75        /// entirety when <see cref="RecnoDatabase.Open"/> is called. If false,
76        /// <see cref="BackingFile"/> may be read lazily.
77        /// </summary>
78        public bool Snapshot;
79        internal new uint flags {
80            get {
81                uint ret = base.flags;
82                ret |= Renumber ? Internal.DbConstants.DB_RENUMBER : 0;
83                ret |= Snapshot ? Internal.DbConstants.DB_SNAPSHOT : 0;
84                return ret;
85            }
86        }
87
88        /// <summary>
89        /// The policy for how to handle database creation.
90        /// </summary>
91        /// <remarks>
92        /// If the database does not already exist and
93        /// <see cref="CreatePolicy.NEVER"/> is set,
94        /// <see cref="RecnoDatabase.Open"/> will fail.
95        /// </remarks>
96        public CreatePolicy Creation;
97        internal new uint openFlags {
98            get {
99                uint flags = base.openFlags;
100                flags |= (uint)Creation;
101                return flags;
102            }
103        }
104
105        /// <summary>
106        /// A function to call after the record number has been selected but
107        /// before the data has been stored into the database.
108        /// </summary>
109        /// <remarks>
110        /// <para>
111        /// When using <see cref="QueueDatabase.Append"/>, it may be useful to
112        /// modify the stored data based on the generated key. If a delegate is
113        /// specified, it will be called after the record number has been
114        /// selected, but before the data has been stored.
115        /// </para>
116        /// </remarks>
117        public AppendRecordDelegate Append;
118
119        internal bool delimiterIsSet;
120        private int delim;
121        /// <summary>
122        /// The delimiting byte used to mark the end of a record in
123        /// <see cref="BackingFile"/>.
124        /// </summary>
125        /// <remarks>
126        /// <para>
127        /// This byte is used for variable length records if
128        /// <see cref="BackingFile"/> is set. If <see cref="BackingFile"/> is
129        /// specified and no delimiting byte was specified, newline characters
130        /// (that is, ASCII 0x0a) are interpreted as end-of-record markers.
131        /// </para>
132        /// <para>
133        /// If the database already exists, this setting will be ignored.
134        /// </para>
135        /// </remarks>
136        public int Delimiter {
137            get { return delim; }
138            set {
139                delimiterIsSet = true;
140                delim = value;
141            }
142        }
143
144        internal bool lengthIsSet;
145        private uint len;
146        /// <summary>
147        /// Specify that the records are fixed-length, not byte-delimited, and
148        /// are of length Length.
149        /// </summary>
150        /// <remarks>
151        /// <para>
152        /// Any records added to the database that are less than Length bytes
153        /// long are automatically padded (see <see cref="PadByte"/> for more
154        /// information).
155        /// </para>
156        /// <para>
157        /// Any attempt to insert records into the database that are greater
158        /// than Length bytes long will cause the call to fail immediately and
159        /// return an error.
160        /// </para>
161        /// <para>
162        /// If the database already exists, this setting will be ignored.
163        /// </para>
164        /// </remarks>
165        public uint Length {
166            get { return len; }
167            set {
168                lengthIsSet = true;
169                len = value;
170            }
171        }
172
173        internal bool padIsSet;
174        private int pad;
175        /// <summary>
176        /// The padding character for short, fixed-length records.
177        /// </summary>
178        /// <remarks>
179        /// <para>
180        /// If no pad character is specified, space characters (that is, ASCII
181        /// 0x20) are used for padding.
182        /// </para>
183        /// <para>
184        /// If the database already exists, this setting will be ignored.
185        /// </para>
186        /// </remarks>
187        public int PadByte {
188            get { return pad; }
189            set {
190                padIsSet = true;
191                pad = value;
192            }
193        }
194
195        /// <summary>
196        /// The underlying source file for the Recno access method.
197        /// </summary>
198        /// <remarks>
199        /// <para>
200        /// The purpose of the source file is to provide fast access and
201        /// modification to databases that are normally stored as flat text
202        /// files.
203        /// </para>
204        /// <para>
205        /// The source parameter specifies an underlying flat text database file
206        /// that is read to initialize a transient record number index. In the
207        /// case of variable length records, the records are separated, as
208        /// specified by <see cref="Delimiter"/>. For example, standard UNIX
209        /// byte stream files can be interpreted as a sequence of variable
210        /// length records separated by newline characters.
211        /// </para>
212        /// <para>
213        /// In addition, when cached data would normally be written back to the
214        /// underlying database file (for example,
215        /// <see cref="BaseDatabase.Close"/> or
216        /// <see cref="BaseDatabase.Sync"/>), the in-memory copy of the
217        /// database will be written back to the source file.
218        /// </para>
219        /// <para>
220        /// By default, the backing source file is read lazily; that is, records
221        /// are not read from the file until they are requested by the
222        /// application. If multiple processes (not threads) are accessing a
223        /// Recno database concurrently, and are either inserting or deleting
224        /// records, the backing source file must be read in its entirety before
225        /// more than a single process accesses the database, and only that
226        /// process should specify the backing source file as part of the
227        /// <see cref="RecnoDatabase.Open"/> call. See <see cref="Snapshot"/>
228        /// for more information.
229        /// </para>
230        /// <para>
231        /// Reading and writing the backing source file specified by source
232        /// cannot be transaction-protected because it involves filesystem
233        /// operations that are not part of the Db transaction methodology. For
234        /// this reason, if a temporary database is used to hold the records, it
235        /// is possible to lose the contents of the source file, for example, if
236        /// the system crashes at the right instant. If a file is used to hold
237        /// the database, normal database recovery on that file can be used to
238        /// prevent information loss, although it is still possible that the
239        /// contents of source will be lost if the system crashes.
240        /// </para>
241        /// <para>
242        /// The source file must already exist (but may be zero-length) when
243        /// <see cref="RecnoDatabase.Open"/> is called.
244        /// </para>
245        /// <para>
246        /// It is not an error to specify a read-only source file when creating
247        /// a database, nor is it an error to modify the resulting database.
248        /// However, any attempt to write the changes to the backing source file
249        /// using either the <see cref="BaseDatabase.Sync"/> or
250        /// <see cref="BaseDatabase.Close"/> methods will fail, of course.
251        /// Use <see cref="BaseDatabase.Close(bool)"/> to stop it from
252        /// attempting to write the changes to the backing file; instead, they
253        /// will be silently discarded.
254        /// </para>
255        /// <para>
256        /// For all of the previous reasons, the source file is generally used
257        /// to specify databases that are read-only for Berkeley DB
258        /// applications; and that are either generated on the fly by software
259        /// tools or modified using a different mechanism � for example, a text
260        /// editor.
261        /// </para>
262        /// <para>
263        /// If the database already exists, BackingFile must be the same as that
264        /// historically used to create the database or corruption can occur.
265        /// </para>
266        /// </remarks>
267        public string BackingFile;
268
269        /// <summary>
270        /// Instantiate a new RecnoDatabaseConfig object
271        /// </summary>
272        public RecnoDatabaseConfig() {
273            Renumber = false;
274            Snapshot = false;
275            Append = null;
276            delimiterIsSet = false;
277            lengthIsSet = false;
278            padIsSet = false;
279            BackingFile = null;
280            Creation = CreatePolicy.NEVER;
281        }
282
283    }
284}