/// <summary> /// This is the main entry point to the thread. /// </summary> private void ThreadEntry() { try { // Reset some values BytesRead = 0; ScoopsRead = 0; ulong utilisedStorage = 0; // Get which files to mine string[] files = Directory.GetFiles(_directory, "*_*_*_*"); byte[] readBuffer = null; List <Scoop> scoops = new List <Scoop>(500); Stopwatch swTotal = new Stopwatch(); swTotal.Start(); // Process each file foreach (string file in files) { // Get handle to file and ensure it is valid Stopwatch sw = new Stopwatch(); sw.Start(); string[] fileParts = Path.GetFileName(file).Split(new char[] { '_' }, 4); ulong accountId; ulong startNonce; ulong numberOfNonces; ulong staggerSize; if (!ulong.TryParse(fileParts[0], out accountId)) { Logger.Error("Unable to parse account ID from " + file); continue; } if (!ulong.TryParse(fileParts[1], out startNonce)) { Logger.Error("Unable to parse start nonce from " + file); continue; } if (!ulong.TryParse(fileParts[2], out numberOfNonces)) { Logger.Error("Unable to parse number of nonces from " + file); continue; } if (!ulong.TryParse(fileParts[3], out staggerSize)) { Logger.Error("Unable to parse stagger size from " + file); continue; } if (staggerSize != numberOfNonces) { Logger.Error("Unoptimised file, will not process " + file); continue; } long expectedSize = (long)(Plot.PLOT_SIZE * numberOfNonces); FileInfo fi = new FileInfo(file); if (fi.Length != expectedSize) { Logger.Error("Plot file is not expected size, skipping " + file); continue; } utilisedStorage += (ulong)expectedSize; // Now we have a good plot file let's take our scoop and for each nonce process it uint desiredBufferSize = (uint)(Plot.SCOOP_SIZE * numberOfNonces); try { using (FileStream stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read)) { // Create our reading buffers uint remainingToRead = desiredBufferSize; uint bufferSize = desiredBufferSize > Configuration.MemoryLimitPerReader ? Configuration.MemoryLimitPerReader : desiredBufferSize; if (readBuffer == null || readBuffer.Length < bufferSize) { readBuffer = new byte[bufferSize]; } // Move to begining for optimized read long offset = (long)(_scoop * desiredBufferSize); stream.Seek(offset, SeekOrigin.Begin); // Keep reading in large chunks up to maximum memory permitted and then handover to have deadline calculated elsewhere ulong currentNonce = startNonce; while (remainingToRead > 0) { uint read = (uint)stream.Read(readBuffer, 0, (int)(remainingToRead > bufferSize ? bufferSize : remainingToRead)); BytesRead += read; remainingToRead -= read; scoops.Clear(); for (uint bufferOffset = 0; bufferOffset < read; bufferOffset += Plot.SCOOP_SIZE, currentNonce++) { scoops.Add(new Scoop(_miningInfo.BlockHeight, currentNonce, accountId, readBuffer, bufferOffset)); ScoopsRead++; } // Notify our callers ScoopsDiscovered?.Invoke(this, new ScoopsDiscoveredEventArgs(scoops)); // Return if we're done if (!_isAlive) { break; } } } } catch (Exception ex) { Logger.Error("Error whilst processing " + file, ex); } sw.Stop(); double secs = sw.Elapsed.TotalSeconds; double bps = desiredBufferSize / secs; double mbps = bps / 1000 / 1000; Logger.Debug(String.Format("Processed {0} in {1} secs = {2} MBps", file, secs, mbps)); // Return if we're done if (!_isAlive) { break; } } Logger.Info(String.Format("Read {0} {3}GB in {1} secs = {2} MBps", _directory, swTotal.Elapsed.TotalSeconds, (BytesRead / 1000 / 1000 / swTotal.Elapsed.TotalSeconds), (decimal)BytesRead / 1000m / 1000m / 1000m)); UtilisedStorage = utilisedStorage / 1000000000m; } catch (Exception ex) { Logger.Error("Failure enumerating \"" + _directory + "\": " + ex.Message); } _isAlive = false; _miningThread = null; }
/// <summary> /// Handle new scoops being discovered and pass it over to the plot checker. /// </summary> /// <param name="sender"> /// The event sender. /// </param> /// <param name="e"> /// The event arguments. /// </param> private void PlotReaderOnScoopsDiscovered(object sender, ScoopsDiscoveredEventArgs e) { ScoopsDiscovered?.Invoke(this, e); }