Esempio n. 1
0
	void file_storage::optimize(int pad_file_limit)
	{
		// the main purpuse of padding is to optimize disk
		// I/O. This is a conservative memory page size assumption
		int alignment = 8*1024;

		// it doesn't make any sense to pad files that
		// are smaller than one piece
		if (pad_file_limit >= 0 && pad_file_limit < alignment)
			pad_file_limit = alignment;

		size_type off = 0;
		int padding_file = 0;
		for (std::vector<internal_file_entry>::iterator i = m_files.begin();
			i != m_files.end(); ++i)
		{
			if ((off & (alignment-1)) == 0)
			{
				// this file position is aligned, pick the largest
				// available file to put here
				std::vector<internal_file_entry>::iterator best_match
					= std::max_element(i, m_files.end()
						, &compare_file_entry_size);

				if (best_match != i)
				{
					int index = file_index(*best_match);
					int cur_index = file_index(*i);
					reorder_file(index, cur_index);
					i = m_files.begin() + cur_index;
				}
			}
			else if (pad_file_limit >= 0
				&& (off & (alignment-1)) != 0
				&& i->size > pad_file_limit
				&& i->pad_file == false)
			{
				// if we have pad files enabled, and this file is
				// not piece-aligned and the file size exceeds the
				// limit, and it's not a padding file itself.
				// so add a padding file in front of it
				int pad_size = alignment - (off & (alignment-1));
				
				// find the largest file that fits in pad_size
				std::vector<internal_file_entry>::iterator best_match = m_files.end();
				for (std::vector<internal_file_entry>::iterator j = i+1; j < m_files.end(); ++j)
				{
					if (j->size > pad_size) continue;
					if (best_match == m_files.end() || j->size > best_match->size)
						best_match = j;
				}

				if (best_match != m_files.end())
				{
					// we found one
					// We cannot have found i, because i->size > pad_file_limit
					// which is forced to be no less than alignment. We only
					// look for files <= pad_size, which never is greater than
					// alignment
					TORRENT_ASSERT(best_match != i);
					int index = file_index(*best_match);
					int cur_index = file_index(*i);
					reorder_file(index, cur_index);
					i = m_files.begin() + cur_index;

					i->offset = off;
					off += i->size;
					continue;
				}

				// we could not find a file that fits in pad_size
				// add a padding file
				// note that i will be set to point to the
				// new pad file. Once we're done adding it, we need
				// to increment i to point to the current file again
				internal_file_entry e;
				i = m_files.insert(i, e);
				i->size = pad_size;
				i->offset = off;
				char name[30];
				snprintf(name, sizeof(name), ".____padding_file/%d", padding_file);
				std::string path = combine_path(m_name, name);
				i->set_name(path.c_str());
				i->pad_file = true;
				off += pad_size;
				++padding_file;
				// skip the pad file we just added and point
				// at the current file again
				++i;
			}
			i->offset = off;
			off += i->size;
		}
		m_total_size = off;
	}
Esempio n. 2
0
	void file_storage::optimize(int pad_file_limit, int alignment)
	{
		// it doesn't make any sense to pad files that
		// are smaller than one block
		if (pad_file_limit >= 0 && pad_file_limit < 0x4000)
			pad_file_limit = 0x4000;

		// also, it doesn't make any sense to pad files
		// that are smaller than the alignment, since they
		// won't get aligned anyway; they are used as padding
		if (pad_file_limit >= 0 && pad_file_limit < alignment)
			pad_file_limit = alignment;

		size_type off = 0;
		int padding_file = 0;
		for (std::vector<internal_file_entry>::iterator i = m_files.begin();
			i != m_files.end(); ++i)
		{
			if ((off & (alignment-1)) == 0)
			{
				// this file position is aligned, pick the largest
				// available file to put here
				std::vector<internal_file_entry>::iterator best_match
					= std::max_element(i, m_files.end()
						, &compare_file_entry_size);

				if (best_match != i)
				{
					int index = file_index(*best_match);
					int cur_index = file_index(*i);
					reorder_file(index, cur_index);
					i = m_files.begin() + cur_index;
				}
			}
			else if (pad_file_limit >= 0
				&& i->size > pad_file_limit
				&& i->pad_file == false)
			{
				// if we have pad files enabled, and this file is
				// not piece-aligned and the file size exceeds the
				// limit, and it's not a padding file itself.
				// so add a padding file in front of it
				int pad_size = alignment - (off & (alignment-1));
				
				// find the largest file that fits in pad_size
				std::vector<internal_file_entry>::iterator best_match = m_files.end();
				for (std::vector<internal_file_entry>::iterator j = i+1; j < m_files.end(); ++j)
				{
					if (j->size > pad_size) continue;
					if (best_match == m_files.end() || j->size > best_match->size)
						best_match = j;
				}

				if (best_match != m_files.end())
				{
					// we found one
					// We cannot have found i, because i->size > pad_file_limit
					// which is forced to be no less than alignment. We only
					// look for files <= pad_size, which never is greater than
					// alignment
					TORRENT_ASSERT(best_match != i);
					int index = file_index(*best_match);
					int cur_index = file_index(*i);
					reorder_file(index, cur_index);
					i = m_files.begin() + cur_index;
					i->offset = off;
					off += i->size;
					continue;
				}

				// we could not find a file that fits in pad_size
				// add a padding file
				// note that i will be set to point to the
				// new pad file. Once we're done adding it, we need
				// to increment i to point to the current file again
				// first add the pad file to the end of the file list
				// then swap it in place. This minimizes the amount
				// of copying of internal_file_entry, which is somewhat
				// expensive (until we have move semantics)
				int cur_index = file_index(*i);
				int index = m_files.size();
				m_files.push_back(internal_file_entry());
				internal_file_entry& e = m_files.back();
				// i may have been invalidated, refresh it
				i = m_files.begin() + cur_index;
				e.size = pad_size;
				e.offset = off;
				char name[30];
				snprintf(name, sizeof(name), ".____padding_file/%d", padding_file);
				std::string path = combine_path(m_name, name);
				e.set_name(path.c_str());
				e.pad_file = true;
				off += pad_size;
				++padding_file;

				if (!m_mtime.empty()) m_mtime.resize(index + 1, 0);
				if (!m_file_hashes.empty()) m_file_hashes.resize(index + 1, NULL);
				if (!m_file_base.empty()) m_file_base.resize(index + 1, 0);

				reorder_file(index, cur_index);

				TORRENT_ASSERT((off & (alignment-1)) == 0);
				continue;
			}
			i->offset = off;
			off += i->size;
		}
		m_total_size = off;
	}