2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 2009, 2012 Oracle and/or its affiliates. All rights reserved.
8 using System.Collections;
9 using System.Collections.Generic;
11 using BerkeleyDB.Internal;
13 namespace BerkeleyDB {
15 /// A class providing access to multiple <see cref="DatabaseEntry"/>
18 public class MultipleDatabaseEntry : DatabaseEntry,
19 IEnumerable<DatabaseEntry> {
20 private bool _recno = false;
22 internal MultipleDatabaseEntry(DatabaseEntry dbt) {
28 /// Construct a new key or data bulk buffer with a formatted byte array.
30 /// <param name="data">The formatted byte array</param>
31 /// <param name="recno">
32 /// Whether it is buffer for keys in <see cref="RecnoDatabase"/> or
33 /// <see cref="QueueDatabase"/>
35 public MultipleDatabaseEntry(byte[] data, bool recno) {
39 flags |= DbConstants.DB_DBT_BULK;
43 /// Construct a new key or data bulk buffer with a bunch of record
44 /// numbers, as keys in <see cref="RecnoDatabase"/> or
45 /// <see cref="QueueDatabase"/>
47 /// <param name="recnos">Enumerable record numbers</param>
48 public MultipleDatabaseEntry(IEnumerable<uint> recnos) {
49 List<byte> list = new List<byte>();
51 byte[] lenArr = BitConverter.GetBytes(4);
57 * The first record number is written at the end of the array,
58 * preceded by its offset in the array and the length of the record
59 * number (the length is always 4 bytes.) Each entry in the array
60 * (record number, offset & length) is 12 bytes.
62 * 0 is an invalid record number and is used to mark the end of the
63 * array of record numbers. Since records are written from the
64 * back of the array, the first 4 bytes of the array are zeros.
65 * -----------------------------------------------------
66 * |0|lengthN|offsetN|recnoN|...|length1|offset1|recno1|
67 * -----------------------------------------------------
69 foreach (uint recno in recnos) {
70 arr = BitConverter.GetBytes(recno);
71 for (i = 0; i < 4; i++)
73 arr = BitConverter.GetBytes(pos);
74 for (i = 0; i < 4; i++)
76 for (i = 0; i < 4; i++)
80 arr = BitConverter.GetBytes(0);
81 for (i = 0; i < 4; i++)
83 for (i = 0; i < list.Count / (2 * 4); i++) {
84 for (j = 0; j < 4; j++) {
85 tmp = list[i * 4 + j];
86 list[i * 4 + j] = list[list.Count - 4 + j - i * 4];
87 list[list.Count - 4 + j - i * 4] = tmp;
90 UserData = list.ToArray();
93 flags |= DbConstants.DB_DBT_BULK;
97 /// Construct a new key or data bulk buffer with a bunch of
98 /// <see cref="DatabaseEntry"/> referring to <paramref name="recno"/>.
100 /// <param name="data">Enumerable data</param>
101 /// <param name="recno">
102 /// Whether it is buffer for keys in <see cref="RecnoDatabase"/>
103 /// or <see cref="QueueDatabase"/>
105 public MultipleDatabaseEntry(
106 IEnumerable<DatabaseEntry> data, bool recno) {
107 List<byte> list = new List<byte>();
108 List<uint> metadata = new List<uint>();
110 byte[] lenArr = BitConverter.GetBytes(4);
118 * For recno DatabaseEntry, everything is stored in the header,
119 * as described in the comment above. The layout, again, is:
120 * -----------------------------------------------------
121 * |0|lengthN|offsetN|recnoN|...|length1|offset1|recno1|
122 * -----------------------------------------------------
124 foreach (DatabaseEntry dbtObj in data) {
126 for (i = 0; i < 4; i++)
128 arr = BitConverter.GetBytes(pos);
129 for (i = 0; i < 4; i++)
131 for (i = 0; i < 4; i++)
135 arr = BitConverter.GetBytes(0);
136 for (i = 0; i < 4; i++)
138 for (i = 0; i < list.Count / (2 * 4); i++) {
139 for (j = 0; j < 4; j++) {
140 tmp = list[i * 4 + j];
141 list[i * 4 + j] = list[list.Count - 4 + j - i * 4];
142 list[list.Count - 4 + j - i * 4] = tmp;
147 * For non-recno DatabaseEntry, the data values are written
148 * sequentially to the start of the array. Header information
149 * is written at the end of the array. Header information is
150 * the offset in the array at which the data value starts and
151 * the length of the data (each header entry occupies 8 bytes.)
152 * The data values are separated from the header information by
153 * a value of -1. The layout is:
154 * ---------------------------------------------------------
155 * |data1|...|dataN||-1|lengthN|offsetN|...|length1|offset1|
156 * ---------------------------------------------------------
158 foreach (DatabaseEntry dbtObj in data) {
163 for (i = 0; i < (int)size; i++)
167 arr = BitConverter.GetBytes(-1);
168 for (i = 0; i < 4; i++)
170 for (i = metadata.Count; i > 0; i--) {
171 arr = BitConverter.GetBytes(metadata[i - 1]);
172 for (j = 0; j < 4; j++)
176 UserData = list.ToArray();
179 flags |= DbConstants.DB_DBT_BULK;
183 /// Return the number of records in the DBT.
191 while ((recno = BitConverter.ToInt32(_data, (int)pos)) != 0) {
197 while ((off = BitConverter.ToInt32(_data, (int)pos)) >= 0) {
207 /// Whether the bulk buffer is for recno or queue database.
210 get { return _recno; }
213 IEnumerator IEnumerable.GetEnumerator() {
214 return GetEnumerator();
218 /// Return an enumerator which iterates over all
219 /// <see cref="DatabaseEntry"/> objects represented by the
220 /// <see cref="MultipleDatabaseEntry"/>.
223 /// An enumerator for the <see cref="MultipleDatabaseEntry"/>
225 public IEnumerator<DatabaseEntry> GetEnumerator() {
230 while ((recno = BitConverter.ToInt32(_data, (int)pos)) != 0) {
231 byte[] arr = new byte[4];
232 Array.Copy(_data, pos, arr, 0, 4);
234 yield return new DatabaseEntry(arr);
238 int off = BitConverter.ToInt32(_data, (int)pos);
239 for (int i = 0; off >= 0;
240 off = BitConverter.ToInt32(_data, (int)pos), i++) {
242 int sz = BitConverter.ToInt32(_data, (int)pos);
243 byte[] arr = new byte[sz];
244 Array.Copy(_data, off, arr, 0, sz);
246 yield return new DatabaseEntry(arr);
251 // public byte[][] Data;
252 /* No Public Constructor */
253 //internal MultipleDatabaseEntry(DatabaseEntry dbt) {
254 // byte[] dat = dbt.UserData;
255 // List<byte[]> tmp = new List<byte[]>();
256 // uint pos = dbt.ulen - 4;
257 // int off = BitConverter.ToInt32(dat, (int)pos);
258 // for (int i = 0; off > 0; off = BitConverter.ToInt32(dat, (int)pos), i++) {
260 // int sz = BitConverter.ToInt32(dat, (int)pos);
261 // tmp.Add(new byte[sz]);
262 // Array.Copy(dat, off, tmp[i], 0, sz);
265 // Data = tmp.ToArray();