/* This file is part of cpp-ethereum. cpp-ethereum is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ /** @file DownloadMan.h * @author Gav Wood * @date 2014 */ #pragma once #include #include #include #include #include #include #include namespace dev { namespace eth { class DownloadMan; class DownloadSub { friend class DownloadMan; public: DownloadSub(DownloadMan& _man); ~DownloadSub(); /// Finished last fetch - grab the next bunch of block hashes to download. h256Hash nextFetch(unsigned _n); /// Note that we've received a particular block. @returns true if we had asked for it but haven't received it yet. bool noteBlock(h256 _hash); /// Nothing doing here. void doneFetch() { resetFetch(); } bool askedContains(unsigned _i) const { Guard l(m_fetch); return m_asked.contains(_i); } RangeMask const& asked() const { return m_asked; } RangeMask const& attemped() const { return m_attempted; } private: void resetFetch() // Called by DownloadMan when we need to reset the download. { Guard l(m_fetch); m_remaining.clear(); m_indices.clear(); m_asked.reset(); m_attempted.reset(); } DownloadMan* m_man = nullptr; mutable Mutex m_fetch; h256Hash m_remaining; std::unordered_map m_indices; RangeMask m_asked; RangeMask m_attempted; }; class DownloadMan { friend class DownloadSub; public: ~DownloadMan() { for (auto i: m_subs) i->m_man = nullptr; } void resetToChain(h256s const& _chain) { { ReadGuard l(x_subs); for (auto i: m_subs) i->resetFetch(); } WriteGuard l(m_lock); m_chain.clear(); m_chain.reserve(_chain.size()); for (auto i = _chain.rbegin(); i != _chain.rend(); ++i) m_chain.push_back(*i); m_blocksGot = RangeMask(0, m_chain.size()); } void reset() { { ReadGuard l(x_subs); for (auto i: m_subs) i->resetFetch(); } WriteGuard l(m_lock); m_chain.clear(); m_blocksGot.reset(); } RangeMask taken(bool _desperate = false) const { ReadGuard l(m_lock); auto ret = m_blocksGot; if (!_desperate) { ReadGuard l(x_subs); for (auto i: m_subs) ret += i->m_asked; } return ret; } bool isComplete() const { ReadGuard l(m_lock); return m_blocksGot.full(); } h256s remaining() const { h256s ret; ReadGuard l(m_lock); for (auto i: m_blocksGot.inverted()) ret.push_back(m_chain[i]); return ret; } size_t chainSize() const { ReadGuard l(m_lock); return m_chain.size(); } size_t chainEmpty() const { ReadGuard l(m_lock); return m_chain.empty(); } void foreachSub(std::function const& _f) const { ReadGuard l(x_subs); for(auto i: m_subs) _f(*i); } unsigned subCount() const { ReadGuard l(x_subs); return m_subs.size(); } RangeMask blocksGot() const { ReadGuard l(m_lock); return m_blocksGot; } private: mutable SharedMutex m_lock; h256s m_chain; RangeMask m_blocksGot; mutable SharedMutex x_subs; std::unordered_set m_subs; }; } }