void ISnapshotStorage.Init()
        {
            if (!Directory.Exists(_path))
            {
                Directory.CreateDirectory(_path);
            }

            var fileName = Path.Combine(_path, _serializer.FileName);

            byte[] buffer;

            Version version;

            if (File.Exists(fileName))
            {
                using (var stream = File.OpenRead(fileName))
                {
                    version = new Version(stream.ReadByte(), stream.ReadByte());

                    buffer = new byte[_serializer.GetSnapshotSize(version)];

                    while (stream.Position < stream.Length)
                    {
                        stream.ReadBytes(buffer, buffer.Length);

                        var message = _serializer.Deserialize(version, buffer);

                        _snapshots.Add(_serializer.GetSecurityId(message), Tuple.Create(stream.Position - buffer.Length, message));
                    }

                    _maxOffset = stream.Position;
                }
            }
            else
            {
                version    = _serializer.Version;
                _maxOffset = 2;                 // version bytes

                buffer = new byte[_serializer.GetSnapshotSize(version)];
            }

            _snapshotSize = buffer.Length;

            var isFlushing = false;

            ThreadingHelper.Timer(() =>
            {
                Tuple <long, TMessage>[] changed;

                lock (_snapshots.SyncRoot)
                {
                    if (_dirtySecurities.Count == 0)
                    {
                        return;
                    }

                    if (isFlushing)
                    {
                        return;
                    }

                    isFlushing = true;

                    changed = _dirtySecurities.Select(id =>
                    {
                        var tuple = _snapshots[id];
                        return(Tuple.Create(tuple.Item1, (TMessage)tuple.Item2.Clone()));
                    }).OrderBy(t => t.Item1).ToArray();

                    _dirtySecurities.Count = 0;
                }

                try
                {
                    using (var stream = File.OpenWrite(fileName))
                    {
                        if (stream.Length == 0)
                        {
                            stream.WriteByte((byte)version.Major);
                            stream.WriteByte((byte)version.Minor);
                        }

                        foreach (var tuple in changed)
                        {
                            stream.Seek(tuple.Item1, SeekOrigin.Begin);

                            Array.Clear(buffer, 0, buffer.Length);
                            _serializer.Serialize(version, tuple.Item2, buffer);

                            stream.Write(buffer, 0, buffer.Length);
                        }
                    }
                }
                catch (Exception ex)
                {
                    ex.LogError();
                }

                lock (_snapshots.SyncRoot)
                    isFlushing = false;
            }).Interval(TimeSpan.FromSeconds(10));
        }