Пример #1
0
        /// <summary>
        /// Add a key/data pair to the database.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="data">The data.</param>
        public void Add(byte[] key, byte[] data)
        {
            if (_file == null)
            {
                throw new ObjectDisposedException(GetType().Name);
            }

            var bytes = new byte[8];

            Cdb.PackInt32((UInt32)key.Length, bytes, 0);
            Cdb.PackInt32((UInt32)data.Length, bytes, 4);

            // Write the record: keylen, datalen, key, data.
            _file.Write(bytes, 0, bytes.Length);
            _file.Write(key, 0, key.Length);
            _file.Write(data, 0, data.Length);

            // Add hash and offset to the in-memory list:
            UInt32 hash = Cdb.Hash(key);

            _hashInfo.Add(new HashPos(hash, _pos));
            _hashSize[hash & 255] += 1;             // one more entry

            // Update the file position pointer:
            AdvancePos(8);             // key and data length
            AdvancePos((UInt32)key.Length);
            AdvancePos((UInt32)data.Length);
        }
Пример #2
0
        private int _loop;         // num of hash slots searched under current key

        /// <summary>
        /// Open a constant database from the given file.
        /// </summary>
        /// <param name="filePath">Path to the CDB file.</param>
        public CdbFile(string filePath)
        {
            _cdbFile = File.OpenRead(filePath);

            _heads = new UInt32[256 * 2];

            var bytes = new byte[2048];

            CdbRead(bytes, bytes.Length);

            for (int i = 0, offset = 0; i < 256; i++)
            {
                UInt32 pos = Cdb.UnpackInt32(bytes, offset);
                offset += 4;
                UInt32 len = Cdb.UnpackInt32(bytes, offset);
                offset += 4;

                _heads[i << 1]       = pos;
                _heads[(i << 1) + 1] = len;
            }

            _loop = 0;
        }
Пример #3
0
        /// <summary>
        /// Find the next record stored under the given <paramref name="key"/>.
        /// </summary>
        /// <returns>The next record stored under the given key,
        /// or <c>null</c> if no more records can be found.</returns>
        public byte[] FindNext(byte[] key)
        {
            // We change object state in here, so nobody must intervene!
            lock (_syncLock)
            {
                if (_cdbFile == null)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                // Initialize: locate hash table and entry in it:
                if (_loop == 0)
                {
                    UInt32 u = Cdb.Hash(key);

                    // Get hash table len&pos for this key:
                    UInt32 slot = u & 255;
                    _hslots = _heads[(slot << 1) + 1];
                    if (_hslots == 0)
                    {
                        return(null);
                    }
                    _hpos = _heads[slot << 1];

                    // Remember this key's hash:
                    _khash = u;

                    // Locate the slot in the table at _hpos:
                    u   >>= 8;
                    u    %= _hslots;
                    u   <<= 3;
                    _kpos = _hpos + u;
                }

                // Search: iterate all hash slots for the given key:
                var bytes = new byte[8];
                while (_loop < _hslots)
                {
                    // Read the entry for this key from the hash slot
                    CdbRead(bytes, 8, _kpos);
                    UInt32 h   = Cdb.UnpackInt32(bytes, 0);
                    UInt32 pos = Cdb.UnpackInt32(bytes, 4);
                    if (pos == 0)
                    {
                        break;
                    }

                    // Advance loop counter and key position.
                    // Wrap key position if at end of hash table.
                    _loop += 1;
                    _kpos += 8;
                    if (_kpos == (_hpos + (_hslots << 3)))
                    {
                        _kpos = _hpos;
                    }

                    // Different hash? Probe next slot...
                    if (h != _khash)
                    {
                        continue;
                    }

                    // Jump to the record and see if key matches:
                    CdbRead(bytes, 8, pos);
                    UInt32 klen = Cdb.UnpackInt32(bytes, 0);
                    if (klen != key.Length)
                    {
                        continue;
                    }
                    if (!CdbMatch(key))
                    {
                        continue;
                    }
                    UInt32 dlen = Cdb.UnpackInt32(bytes, 4);

                    // Keys match: fetch the data
                    var data = new byte[dlen];
                    CdbRead(data, data.Length);
                    return(data);
                }

                return(null);                // No such key
            }
        }
Пример #4
0
        private void Finish()
        {
            // Find the start of each hash table
            var    tableStart = new UInt32[256];
            UInt32 start      = 0;

            for (int i = 0; i < 256; i++)
            {
                start        += _hashSize[i];
                tableStart[i] = start;
            }

            // Create a new hash info table in order by hash table
            var table = new HashPos[_hashInfo.Count];

            foreach (var hp in _hashInfo)
            {
                table[--tableStart[hp.Hash & 255]] = hp;
            }

            var eightBytes = new byte[8];
            var fixedTable = new byte[2048];

            // Append each of the hash tables to the end of the file.
            // Along the way, build the fixed table (to be written later).
            for (int i = 0; i < 256; i++)
            {
                UInt32 len = _hashSize[i] * 2;               // len of i-th hash table

                // Remember pos and len of i-th hash table in fixed table:
                Cdb.PackInt32(_pos, fixedTable, i * 8);
                Cdb.PackInt32(len, fixedTable, i * 8 + 4);

                // Build the i-th hash table:
                UInt32 tableIndex = tableStart[i];
                var    hashTable  = new HashPos[len];
                for (uint u = 0; u < _hashSize[i]; u++)
                {
                    HashPos hp = table[tableIndex++];

                    // Locate a free entry in the hash table:
                    UInt32 where = (hp.Hash >> 8) % len;
                    while (hashTable[where].Pos != 0)
                    {
                        if (++where == len)
                        {
                            where = 0;                                         // wrap around
                        }
                    }

                    hashTable[where] = hp;                     // and store the (hash,pos) pair
                }

                // Append to the end of the CDB file:
                for (uint u = 0; u < len; u++)
                {
                    Cdb.PackInt32(hashTable[u].Hash, eightBytes, 0);
                    Cdb.PackInt32(hashTable[u].Pos, eightBytes, 4);

                    _file.Write(eightBytes, 0, 8);
                    AdvancePos(8);
                }
            }

            // Rewind to the start of the file and write the fixed-size table:
            _file.Seek(0, SeekOrigin.Begin);
            _file.Write(fixedTable, 0, fixedTable.Length);
        }