/** * Copyright (C) 2004-2005 Alo Sarv <madcat_@users.sourceforge.net> * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <hn/range.h> #include <boost/filesystem/path.hpp> #include <boost/weak_ptr.hpp> #include <map> #include <list> class SharedFile; class HashBase; class PartData { class UsedRange; class LockedRange; public: /** * \brief Construct a NEW temporary file * * Using this constructor, a new temporary file is constructed, at * specified location with specified size. * * @param size Size of the resulting file. * @param loc Location on disk where to store the temp file * @param dest Destination where to write the complete file * * \note The disk space indicated by @param size is not allocated on * actual disk right away. Instead, the size is allocated * dynamically as the file grows. This can be changed from global * application preferences though. */ PartData( uint64_t size, const boost::filesystem::path &loc, const boost::filesystem::path &dest ); /** * \brief Load a previously constructed temporary file. * * This method can be used to resume a previously started download, by * reading the necessery data from @param loc. * * @param loc Path to PartData reference file, which contains the * data required to resume the download. */ PartData(const boost::filesystem::path &loc); /** * \brief Add an availability chunk mask * * Allows modules to register chunk availability maps, so PartData * can decide the lowest-available chunk to be returned from get* * methods * * @param chunkSize Size of one chunk * @param chunks Boolean vector, where each true indicates * the source having the part, and false the source * not having the part. */ void addSourceMask(uint32_t chunkSize, const std::vector<bool> &chunks); /** * \brief Optimized version of addSourceMask(), adds a full source. * * Similar to addSourceMask(), this adds a source which has the entire * file. * * @param chunkSize Size of one chunk */ void addFullSource(uint32_t chunkSize); /** * Gets a free range that PartData considers most important. First/last * ranges are considered important, as well as rare ranges, and * incomplete ranges. * * @param size Size of the range to be aquired. * @return Pointer to a range marked as 'used'. * * \note The size of the given range my be smaller than was requested. */ boost::shared_ptr<UsedRange> getRange(uint32_t size); //! Write method simply writes data starting at specified offset. If //! there are no locks currently on the range, and the range is indeed //! incomplete, everything works. If something goes wrong, exceptions //! will be generated. void write(uint64_t beginOffset, const std::string &data); //! Check for completeness, either the entire file (used internally), or //! a specific subrange (also used internally). Public only for //! completeness. bool isComplete() const; bool isComplete(const Range64 &subRange) const; uint32_t getChunkCount(uint32_t chunkSize) const; private: friend class SharedFile; friend int test_main(int, char[]); //! Copying part files is not allowed PartData(const PartData&); PartData& operator=(const PartData&); //! Only allowed by SharedFile ~PartData(); //! UsedRange concept is similar to many thread libraries lock object //! concepts - you retrieve one via get() methods in PartData, and when //! it is destroyed, it takes care that all used/locked ranges do get //! freed properly. This object may only be used when wrapped in //! boost::shared_ptr. class UsedRange : public Range64 { public: std::auto_ptr<LockedRange> getLock(uint32_t size); private: friend struct boost::checked_deleter<UsedRange>; friend class PartData; //! Allowed only by PartData. UsedRange keeps a pointer back to //! its parent object, and also sets up event handers as //! neccesery to ensure the pointer remains valid. UsedRange(PartData *parent); //! Destruction is only allowed by PartData (not used) and //! boost::checked_deleter, which is used by shared_ptr wrapper. ~UsedRange(); //! copying is not allowed UsedRange(const UsedRange&); UsedRange& operator=(const UsedRange&); //! Ranges that are locked within this usedrange RangeList64 m_locked; }; class LockedRange : public Range64 { public: //! Identical method as in PartData class, this is provided for //! completeness. void write(uint64_t beginOffset, const std::string &data); }; class HashRange : public Range64 { public: HashRange(uint64_t begin, uint64_t end, HashBase *hash); private: HashBase *m_hash; bool m_verified; }; void checkAddChunkMap(uint32_t chunkSize); //! All that are complete RangeList64 m_complete; //! We keep weak references to all used ranges we have given out, for //! cases where we end up needing to return one of these (e.g. no other //! range can be found). std::list<boost::weak_ptr<UsedRange> > m_used; //! Availability map. Outer key is chunksize, internal vector contains //! number of times a chunk has been seen on net. std::map<uint32_t, std::vector<uint32_t> > m_avail; RangeList<HashRange> m_hashes; uint64_t m_size; boost::filesystem::path m_location; boost::filesystem::path m_destination; };