Beispiel #1
0
        private int CalculateBucketOffset(QdbmKey key, out int bucketId)
        {
            bucketId = (int)(key.GetHashCode() % _qdbmHeader.BucketNumber);
            var bucketOffset = Constants.OffsetBuckets + bucketId * sizeof(int);

            return(bucketOffset);
        }
Beispiel #2
0
        public void Put(QdbmKey key, byte[] value)
        {
            if (key == null || key.KeyBytes.Length == 0)
            {
                throw new ArgumentException("key must be specified", nameof(key));
            }

            if (value == null || value.Length == 0)
            {
                throw new ArgumentException("value must be specified", nameof(value));
            }

            _databaseStream.Seek(Constants.OffsetHeaderRecordCount, SeekOrigin.Begin);

            var existingRecordHeader = GetRecordHeader(key);

            var keySize   = key.KeyBytes.Length;
            var valueSize = value.Length;

            var recordHeader = new QdbmRecordHeader
            {
                KeySize   = keySize,
                ValueSize = valueSize
            };

            var record = new QdbmRecord(key, recordHeader, value);

            if (existingRecordHeader?.Size >= recordHeader.Size)
            {
                record.Header.Offset = existingRecordHeader.Offset;
                WriteRecordToDbStream(record);
            }
            else
            {
                AppendRecordToDbStream(record);
            }

            var recordOffset = record.Header.Offset;

            var bucketOffset = CalculateBucketOffset(record.Key, out var bucketId);

            _databaseStream.Seek(bucketOffset, SeekOrigin.Begin);

            var existingRecordOffset = _databaseBinaryReader.ReadInt32();

            if (existingRecordOffset == 0)
            {
                _databaseStream.Seek(bucketOffset, SeekOrigin.Begin);
                _databaseBinaryWriter.Write(recordOffset);

                _buckets[bucketId] = bucketOffset;
            }
            else
            {
                SetChildOffset(record.Key.SecondaryHashCode, existingRecordOffset, recordOffset);
            }
        }
Beispiel #3
0
        private QdbmRecord ReadRecord(QdbmRecordHeader recordHeader)
        {
            _databaseStream.Seek(recordHeader.Offset + Constants.OffsetRecordKeyOffset, SeekOrigin.Begin);

            var key   = _databaseBinaryReader.ReadBytes(recordHeader.KeySize);
            var value = _databaseBinaryReader.ReadBytes(recordHeader.ValueSize);

            var qdbmKey = new QdbmKey(key);

            if (qdbmKey.SecondaryHashCode != recordHeader.SecondHashValue)
            {
                throw new InvalidOperationException("Database is corrupt.");
            }

            var qdbmRecord = new QdbmRecord(qdbmKey, recordHeader, value);

            return(qdbmRecord);
        }
Beispiel #4
0
        public byte[] Get(QdbmKey key)
        {
            var header = GetRecordHeader(key);

            if (header == null)
            {
                return(null);
            }

            var record = ReadRecord(header);

            if (record.Key.KeyBytes.Length == key.KeyBytes.Length &&
                record.Key.KeyBytes.SequenceEqual(key.KeyBytes))
            {
                return(record.Value);
            }

            return(null);
        }
Beispiel #5
0
        private QdbmRecordHeader GetRecordHeader(QdbmKey key)
        {
            var bucketOffset = CalculateBucketOffset(key, out _);

            _databaseStream.Seek(bucketOffset, SeekOrigin.Begin);
            var recordOffset = _databaseBinaryReader.ReadInt32();

            if (recordOffset == 0)
            {
                return(null);
            }

            var header = ReadRecordHeader(recordOffset);

            while (true)
            {
                if (header.LeftChildOffset != 0 && key.SecondaryHashCode > header.SecondHashValue)
                {
                    header = ReadRecordHeader(header.LeftChildOffset);
                    continue;
                }

                if (header.RightChildOffset != 0 && key.SecondaryHashCode < header.SecondHashValue)
                {
                    header = ReadRecordHeader(header.RightChildOffset);
                    continue;
                }

                break;
            }

            if (header.SecondHashValue != key.SecondaryHashCode)
            {
                return(null);
            }

            return(header);
        }
Beispiel #6
0
 public QdbmRecord(QdbmKey key, QdbmRecordHeader header, byte[] value)
 {
     Key    = key;
     Header = header;
     Value  = value;
 }