public MessageProcessor(
            MainContext mainContext,
            MainStorage mainStorage,
            DomainParser parser,
            MainPool mainPool,
            GroupPreprocessor groupPreprocessor,
            NewAccountProcessor newAccountProcessor,
            EditAccountProcessor editAccountProcessor,
            NewLikesProcessor newLikesProcessor,
            DataLoader dataLoader)
        {
            _context           = mainContext;
            _storage           = mainStorage;
            _parser            = parser;
            _pool              = mainPool;
            _groupPreprocessor = groupPreprocessor;

            var newAccountObservable = newAccountProcessor
                                       .DataReceived;

            var editAccountObservable = editAccountProcessor
                                        .DataReceived;

            var newLikesObservable = newLikesProcessor
                                     .DataReceived;


            _likeWorker = new SingleThreadWorker <LikeEvent>(ProcessLike, "Like thread started");
            _loadWorker = new SingleThreadWorker <LoadEvent>(LoadAccount, "Import thread started");
            _postWorker = new SingleThreadWorker <PostEvent>(PostProcess, "Post thread started");

            _importGcSubscription = dataLoader
                                    .CallGc
                                    .Subscribe(_ => {
                _loadWorker.Enqueue(LoadEvent.GC);
            });

            _likeLoadedSubscription = dataLoader
                                      .LikeLoaded
                                      .Subscribe(
                x => _likeWorker.Enqueue(new LikeEvent(x, true)),
                _ => {},
                () => _likeWorker.Enqueue(LikeEvent.EndEvent)
                );

            _dataLoaderSubscription = dataLoader
                                      .AccountLoaded
                                      .Subscribe(
                item => { _loadWorker.Enqueue(new LoadEvent(item)); },
                _ => {},
                () => { _loadWorker.Enqueue(LoadEvent.EndEvent); });

            _newAccountProcessorSubscription = newAccountObservable
                                               .Subscribe(x => { _postWorker.Enqueue(PostEvent.Add(x)); });

            _editAccountProcessorSubscription = editAccountObservable
                                                .Subscribe(x => { _postWorker.Enqueue(PostEvent.Edit(x)); });

            _newLikesProcessorSubscription = newLikesObservable
                                             .Subscribe(NewLikes);

            var updateObservable = newAccountObservable
                                   .Select(_ => Interlocked.Increment(ref _editQuery))
                                   .Merge(editAccountObservable.Select(_ => Interlocked.Increment(ref _editQuery)))
                                   .Merge(newLikesObservable.Select(_ => Interlocked.Increment(ref _editQuery)));

            _secondPhaseEndSubscription = updateObservable
                                          .Throttle(TimeSpan.FromMilliseconds(2000))
                                          .Subscribe(_ =>
            {
                _postWorker.Enqueue(PostEvent.End());
                _likeWorker.Enqueue(LikeEvent.EndEvent);
            });
        }
        public GroupPreprocessor(
            MainContext mainContext,
            MainStorage mainStorage,
            MainPool mainPool)
        {
            _context = mainContext;
            _storage = mainStorage;
            _pool    = mainPool;

            _worker = new SingleThreadWorker <Request>(r => {
                if (r.PostEnded)
                {
                    CompressImpl();
                    DataConfig.GroupUpdates = false;
                    return;
                }

                if (r.ImportEnded)
                {
                    LoadEndedImpl();
                    return;
                }

                if (r.IsLoad)
                {
                    AddImpl(r.Dto, true);
                    return;
                }

                DataConfig.GroupUpdates = true;

                if (r.IsAdd)
                {
                    AddImpl(r.Dto, false);
                }
                else
                {
                    UpdateImpl(r.Dto);
                }
            }, "Group thread started");

            for (int i = 1; i < 32; i++)
            {
                GroupKey keys = (GroupKey)i;

                int initialCapacity = 1;
                if (keys.HasFlag(GroupKey.Sex))
                {
                    initialCapacity *= 2;
                }

                if (keys.HasFlag(GroupKey.Status))
                {
                    initialCapacity *= 3;
                }

                if (keys.HasFlag(GroupKey.City))
                {
                    initialCapacity *= 700;
                }

                if (keys.HasFlag(GroupKey.Country))
                {
                    initialCapacity *= 100;
                }

                if (keys.HasFlag(GroupKey.Interest))
                {
                    initialCapacity *= 160;
                }

                initialCapacity = Math.Min(initialCapacity, DataConfig.MaxId);

                _data[keys] = new SortedSet <GroupBucket>(GroupBucketComparer.Default);
            }
        }