fix issue where paths were not correctly coalesced when adding files to file_storage (used more memory than necessary)

This commit is contained in:
arvidn 2017-08-09 14:01:10 +02:00 committed by Arvid Norberg
parent dbea43ab35
commit 4e497e1383
3 changed files with 61 additions and 24 deletions

View File

@ -583,6 +583,8 @@ namespace libtorrent
private: private:
int get_or_add_path(char const* branch_path, int branch_len);
void add_pad_file(int size void add_pad_file(int size
, std::vector<internal_file_entry>::iterator& i , std::vector<internal_file_entry>::iterator& i
, boost::int64_t& offset , boost::int64_t& offset

View File

@ -47,10 +47,8 @@ POSSIBILITY OF SUCH DAMAGE.
#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2) #if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2)
#define TORRENT_SEPARATOR '\\' #define TORRENT_SEPARATOR '\\'
#define TORRENT_SEPARATOR_STR "\\"
#else #else
#define TORRENT_SEPARATOR '/' #define TORRENT_SEPARATOR '/'
#define TORRENT_SEPARATOR_STR "/"
#endif #endif
namespace libtorrent namespace libtorrent
@ -138,13 +136,14 @@ namespace libtorrent
return fe1.size < fe2.size; return fe1.size < fe2.size;
} }
bool compare_file_offset(internal_file_entry const& lhs bool compare_file_offset(internal_file_entry const& lhs
, internal_file_entry const& rhs) , internal_file_entry const& rhs)
{ {
return lhs.offset < rhs.offset; return lhs.offset < rhs.offset;
}
} }
}
// path is not supposed to include the name of the torrent itself. // path is not supposed to include the name of the torrent itself.
void file_storage::update_path_index(internal_file_entry& e void file_storage::update_path_index(internal_file_entry& e
, std::string const& path, bool set_name) , std::string const& path, bool set_name)
@ -193,6 +192,16 @@ namespace libtorrent
e.no_root_dir = true; e.no_root_dir = true;
} }
e.path_index = get_or_add_path(branch_path, branch_len);
if (set_name) e.set_name(leaf);
}
int file_storage::get_or_add_path(char const* branch_path, int branch_len)
{
// trim trailing slashes
if (branch_len > 0 && branch_path[branch_len-1] == TORRENT_SEPARATOR)
--branch_len;
// do we already have this path in the path list? // do we already have this path in the path list?
std::vector<std::string>::reverse_iterator p std::vector<std::string>::reverse_iterator p
= std::find_if(m_paths.rbegin(), m_paths.rend() = std::find_if(m_paths.rbegin(), m_paths.rend()
@ -201,23 +210,16 @@ namespace libtorrent
if (p == m_paths.rend()) if (p == m_paths.rend())
{ {
// no, we don't. add it // no, we don't. add it
e.path_index = m_paths.size(); int const ret = int(m_paths.size());
TORRENT_ASSERT(branch_path[0] != '/'); TORRENT_ASSERT(branch_len == 0 || branch_path[0] != TORRENT_SEPARATOR);
m_paths.push_back(std::string(branch_path, branch_len));
// trim trailing slashes return ret;
if (branch_len > 0 && branch_path[branch_len-1] == TORRENT_SEPARATOR)
--branch_len;
// poor man's emplace back
m_paths.resize(m_paths.size() + 1);
m_paths.back().assign(branch_path, branch_len);
} }
else else
{ {
// yes we do. use it // yes we do. use it
e.path_index = p.base() - m_paths.begin() - 1; return int(p.base() - m_paths.begin() - 1);
} }
if (set_name) e.set_name(leaf);
} }
#ifndef TORRENT_NO_DEPRECATE #ifndef TORRENT_NO_DEPRECATE
@ -396,6 +398,8 @@ namespace libtorrent
int file_storage::file_index_at_offset(boost::int64_t offset) const int file_storage::file_index_at_offset(boost::int64_t offset) const
{ {
TORRENT_ASSERT_PRECOND(offset >= 0);
TORRENT_ASSERT_PRECOND(offset < m_total_size);
// find the file iterator and file offset // find the file iterator and file offset
internal_file_entry target; internal_file_entry target;
target.offset = offset; target.offset = offset;
@ -425,6 +429,8 @@ namespace libtorrent
, boost::int64_t const offset , boost::int64_t const offset
, int size) const , int size) const
{ {
TORRENT_ASSERT_PRECOND(piece >= 0);
TORRENT_ASSERT_PRECOND(piece < num_pieces());
TORRENT_ASSERT_PRECOND(num_files() > 0); TORRENT_ASSERT_PRECOND(num_files() > 0);
std::vector<file_slice> ret; std::vector<file_slice> ret;
@ -1067,11 +1073,10 @@ namespace libtorrent
i = m_files.begin() + cur_index; i = m_files.begin() + cur_index;
e.size = size; e.size = size;
e.offset = offset; e.offset = offset;
char name[30]; e.path_index = get_or_add_path(".pad", 4);
snprintf(name, sizeof(name), ".pad" TORRENT_SEPARATOR_STR "%d" char name[15];
, pad_file_counter); snprintf(name, sizeof(name), "%d", pad_file_counter);
std::string path = combine_path(m_name, name); e.set_name(name);
e.set_name(path.c_str());
e.pad_file = true; e.pad_file = true;
offset += size; offset += size;
++pad_file_counter; ++pad_file_counter;

View File

@ -75,6 +75,36 @@ void setup_test_storage(file_storage& st)
TEST_EQUAL(st.num_pieces(), (100000 + 0x3fff) / 0x4000); TEST_EQUAL(st.num_pieces(), (100000 + 0x3fff) / 0x4000);
} }
TORRENT_TEST(coalesce_path)
{
file_storage st;
st.add_file(combine_path("test", "a"), 10000);
TEST_EQUAL(st.paths().size(), 1);
TEST_EQUAL(st.paths()[0], "");
st.add_file(combine_path("test", "b"), 20000);
TEST_EQUAL(st.paths().size(), 1);
TEST_EQUAL(st.paths()[0], "");
st.add_file(combine_path("test", combine_path("c", "a")), 30000);
TEST_EQUAL(st.paths().size(), 2);
TEST_EQUAL(st.paths()[0], "");
TEST_EQUAL(st.paths()[1], "c");
// make sure that two files with the same path shares the path entry
st.add_file(combine_path("test", combine_path("c", "b")), 40000);
TEST_EQUAL(st.paths().size(), 2);
TEST_EQUAL(st.paths()[0], "");
TEST_EQUAL(st.paths()[1], "c");
// cause pad files to be created, to make sure the pad files also share the
// same path entries
st.optimize(0, 1024, true);
TEST_EQUAL(st.paths().size(), 3);
TEST_EQUAL(st.paths()[0], "");
TEST_EQUAL(st.paths()[1], "c");
TEST_EQUAL(st.paths()[2], ".pad");
}
TORRENT_TEST(rename_file) TORRENT_TEST(rename_file)
{ {
// test rename_file // test rename_file