private int CalculateBucketOffset(QdbmKey key, out int bucketId) { bucketId = (int)(key.GetHashCode() % _qdbmHeader.BucketNumber); var bucketOffset = Constants.OffsetBuckets + bucketId * sizeof(int); return(bucketOffset); }
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); } }
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); }
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); }
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); }
public QdbmRecord(QdbmKey key, QdbmRecordHeader header, byte[] value) { Key = key; Header = header; Value = value; }