예제 #1
0
        // inserts a key/value into an existing space
        // if necessary, splits the space into two (used/free)
        // NOTE - only call this method from inside a lock {} block
        private void InsertIntoDisk(Hash key, byte[] value, DiskEntry entry)
        {
            InitStream();

            if (_stream.Position != entry.Offset)
            {
                _stream.Seek(entry.Offset, SeekOrigin.Begin);
            }

            _stream.Write(value, 0, value.Length);
            _stream.Flush();

            var diff = entry.Length - value.Length;

            if (diff > 0)
            {
                var free = new DiskEntry()
                {
                    Offset = (uint)(entry.Offset + value.Length), Length = (uint)diff
                };

                _freeSpace.Add(free);
            }

            _entries[key] = new DiskEntry()
            {
                Offset = entry.Offset, Length = (uint)value.Length
            };
            RequestUpdate(key);
        }
예제 #2
0
        public void SetValue(Hash key, byte[] value)
        {
            Throw.If(!_ready, "not ready");

            if (value == null || value.Length == 0)
            {
                Remove(key);
                return;
            }

            if (ContainsKey(key))
            {
                DiskEntry entry;
                lock (_lock)
                {
                    entry = _entries[key];

                    // check if we can fit this in the previous occupied space
                    if (entry.Length >= value.Length)
                    {
                        InsertIntoDisk(key, value, entry);
                        return;
                    }
                    else
                    {
                        // we cant fit it into the previous space, so mark the previous space as free
                        _freeSpace.Add(entry);
                    }
                }
            }

            int  freeSpaceIndex = -1;
            uint min            = uint.MaxValue;

            lock (_lock)
            {
                // search for the minimum free space that can fit this new entry
                for (int i = 0; i < _freeSpace.Count; i++)
                {
                    var entry = _freeSpace[i];
                    if (entry.Length >= value.Length && entry.Length < min)
                    {
                        min            = entry.Length;
                        freeSpaceIndex = i;
                    }
                }
            }

            if (freeSpaceIndex >= 0)
            {
                lock (_lock)
                {
                    var entry = _freeSpace[freeSpaceIndex];
                    _freeSpace.RemoveAt(freeSpaceIndex);
                    InsertIntoDisk(key, value, entry);
                }
            }
            else // nothing found, we need to alloc more disk space here
            {
                lock (_lock)
                {
                    InitStream();
                    _stream.Seek(0, SeekOrigin.End);

                    var entry = new DiskEntry()
                    {
                        Length = (uint)value.Length, Offset = (uint)_stream.Position
                    };
                    InsertIntoDisk(key, value, entry);
                }
            }
        }
예제 #3
0
        public void ReadBlocks()
        {
            lock (_lock)
            {
                InitStream();

                _entries.Clear();
                _freeSpace.Clear();

                if (_stream.Length > 0)
                {
                    _stream.Seek(0, SeekOrigin.Begin);

                    using (var reader = new BinaryReader(_stream, Encoding.ASCII, true))
                    {
                        //uint nextOffset = (uint)(_stream.Length - _header.Length);
                        uint blockOffset = reader.ReadUInt32();
                        _lastBlockOffset = blockOffset;

                        while (blockOffset > 0)
                        {
                            _stream.Seek(blockOffset, SeekOrigin.Begin);

                            var temp = reader.ReadBytes(_header.Length);
                            Throw.If(!temp.SequenceEqual(_header), "header mark expected");

                            var entryCount = reader.ReadUInt32();
                            while (entryCount > 0)
                            {
                                var  hash     = reader.ReadHash();
                                uint location = reader.ReadUInt32();

                                uint size;
                                switch (DataSize)
                                {
                                case KeyStoreDataSize.Small: size = reader.ReadByte(); break;

                                case KeyStoreDataSize.Medium: size = reader.ReadUInt16(); break;

                                case KeyStoreDataSize.Large: size = reader.ReadUInt24(); break;

                                case KeyStoreDataSize.Huge: size = reader.ReadUInt32(); break;

                                default: throw new Exception("unsupported data size");
                                }

                                if (!_entries.ContainsKey(hash))
                                {
                                    _entries[hash] = new DiskEntry()
                                    {
                                        Length = size, Offset = location
                                    };
                                }

                                entryCount--;
                            }

                            blockOffset = reader.ReadUInt32();
                        }
                    }
                }
                else
                {
                    this._lastBlockOffset = 0;
                }
            }
        }