private void EnqueueJobs(NodeBlocksRepository repo, ChainBase chain, CloudBlockBlob blobLock, string lease) { int cumul = 0; ChainedBlock from = chain.Genesis; int blockCount = 0; foreach (var block in repo.GetBlocks(new[] { chain.Genesis }.Concat(chain.EnumerateAfter(chain.Genesis)).Where(c => c.Height % BlockGranularity == 0).Select(c => c.HashBlock), default(CancellationToken))) { cumul += block.Transactions.Count * BlockGranularity; blockCount += BlockGranularity; if (cumul > TransactionsPerWork) { var nextFrom = chain.GetBlock(chain.GetBlock(block.GetHash()).Height + BlockGranularity); if (nextFrom == null) { break; } EnqueueRange(chain, from, blockCount); from = nextFrom; blockCount = 0; cumul = 0; } } blockCount = (chain.Tip.Height - from.Height) + 1; EnqueueRange(chain, from, blockCount); var bytes = chain.Tip.GetLocator().ToBytes(); blobLock.UploadText(Encoders.Hex.EncodeData(bytes), null, new AccessCondition() { LeaseId = lease }); }
public int Run(ChainBase chain = null) { ListenerTrace.Info("Start initial indexing"); int totalProcessed = 0; using (var node = _Conf.Indexer.ConnectToNode(false)) { ListenerTrace.Info("Handshaking..."); node.VersionHandshake(); ListenerTrace.Info("Handshaked"); chain = chain ?? node.GetChain(); ListenerTrace.Info("Current chain at height " + chain.Height); var blockRepository = new NodeBlocksRepository(node); var blobLock = GetInitBlob(); string lease = null; try { blobLock.UploadText("Enqueuing"); lease = blobLock.AcquireLease(null, null); } catch (StorageException) { } if (lease != null) { ListenerTrace.Info("Queueing index jobs"); EnqueueJobs(blockRepository, chain, blobLock, lease); } ListenerTrace.Info("Dequeuing index jobs"); while (true) { var msg = _Conf.Topics .InitialIndexing .ReceiveAsync(TimeSpan.FromMilliseconds(1000)) .Result; var ns = _Conf.Topics.InitialIndexing.GetNamespace(); var description = ns.GetQueue(_Conf.Topics.InitialIndexing.Queue); Console.WriteLine("Work remaining in the queue : " + description.MessageCountDetails.ActiveMessageCount); if (msg == null) { var state = blobLock.DownloadText(); if (state == "Enqueuing" || description.MessageCountDetails.ActiveMessageCount != 0) { ListenerTrace.Info("Additional work will be enqueued..."); continue; } else { var locator = new BlockLocator(); locator.FromBytes(Encoders.Hex.DecodeData(state)); UpdateCheckpoints(locator); break; } } using (msg.Message) { var range = msg.Body; using (var sched = new CustomThreadPoolTaskScheduler(50, 100, range.ToString())) { ListenerTrace.Info("Processing " + range.ToString()); totalProcessed++; var task = _IndexTasks[range.Target]; BlockFetcher fetcher = new BlockFetcher(task.Item1, blockRepository, chain) { FromHeight = range.From, ToHeight = range.From + range.Count - 1 }; try { task.Item2.SaveProgression = false; task.Item2.EnsureIsSetup = totalProcessed == 0; var index = Task.Factory.StartNew(() => { task.Item2.Index(fetcher, sched); }, TaskCreationOptions.LongRunning); while (!index.Wait(TimeSpan.FromMinutes(4))) { msg.Message.RenewLock(); ListenerTrace.Info("Lock renewed"); } } catch (AggregateException aex) { ExceptionDispatchInfo.Capture(aex.InnerException).Throw(); throw; } range.Processed = true; msg.Message.Complete(); } } } } ListenerTrace.Info("Initial indexing terminated"); return(totalProcessed); }