Skip to content

Commit 4e497e1

Browse files
committed
fix issue where paths were not correctly coalesced when adding files to file_storage (used more memory than necessary)
1 parent dbea43a commit 4e497e1

File tree

3 files changed

+61
-24
lines changed

3 files changed

+61
-24
lines changed

include/libtorrent/file_storage.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,8 @@ namespace libtorrent
583583

584584
private:
585585

586+
int get_or_add_path(char const* branch_path, int branch_len);
587+
586588
void add_pad_file(int size
587589
, std::vector<internal_file_entry>::iterator& i
588590
, boost::int64_t& offset

src/file_storage.cpp

+29-24
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,8 @@ POSSIBILITY OF SUCH DAMAGE.
4747

4848
#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2)
4949
#define TORRENT_SEPARATOR '\\'
50-
#define TORRENT_SEPARATOR_STR "\\"
5150
#else
5251
#define TORRENT_SEPARATOR '/'
53-
#define TORRENT_SEPARATOR_STR "/"
5452
#endif
5553

5654
namespace libtorrent
@@ -138,13 +136,14 @@ namespace libtorrent
138136
return fe1.size < fe2.size;
139137
}
140138

141-
bool compare_file_offset(internal_file_entry const& lhs
142-
, internal_file_entry const& rhs)
143-
{
144-
return lhs.offset < rhs.offset;
145-
}
139+
bool compare_file_offset(internal_file_entry const& lhs
140+
, internal_file_entry const& rhs)
141+
{
142+
return lhs.offset < rhs.offset;
146143
}
147144

145+
}
146+
148147
// path is not supposed to include the name of the torrent itself.
149148
void file_storage::update_path_index(internal_file_entry& e
150149
, std::string const& path, bool set_name)
@@ -193,6 +192,16 @@ namespace libtorrent
193192
e.no_root_dir = true;
194193
}
195194

195+
e.path_index = get_or_add_path(branch_path, branch_len);
196+
if (set_name) e.set_name(leaf);
197+
}
198+
199+
int file_storage::get_or_add_path(char const* branch_path, int branch_len)
200+
{
201+
// trim trailing slashes
202+
if (branch_len > 0 && branch_path[branch_len-1] == TORRENT_SEPARATOR)
203+
--branch_len;
204+
196205
// do we already have this path in the path list?
197206
std::vector<std::string>::reverse_iterator p
198207
= std::find_if(m_paths.rbegin(), m_paths.rend()
@@ -201,23 +210,16 @@ namespace libtorrent
201210
if (p == m_paths.rend())
202211
{
203212
// no, we don't. add it
204-
e.path_index = m_paths.size();
205-
TORRENT_ASSERT(branch_path[0] != '/');
206-
207-
// trim trailing slashes
208-
if (branch_len > 0 && branch_path[branch_len-1] == TORRENT_SEPARATOR)
209-
--branch_len;
210-
211-
// poor man's emplace back
212-
m_paths.resize(m_paths.size() + 1);
213-
m_paths.back().assign(branch_path, branch_len);
213+
int const ret = int(m_paths.size());
214+
TORRENT_ASSERT(branch_len == 0 || branch_path[0] != TORRENT_SEPARATOR);
215+
m_paths.push_back(std::string(branch_path, branch_len));
216+
return ret;
214217
}
215218
else
216219
{
217220
// yes we do. use it
218-
e.path_index = p.base() - m_paths.begin() - 1;
221+
return int(p.base() - m_paths.begin() - 1);
219222
}
220-
if (set_name) e.set_name(leaf);
221223
}
222224

223225
#ifndef TORRENT_NO_DEPRECATE
@@ -396,6 +398,8 @@ namespace libtorrent
396398

397399
int file_storage::file_index_at_offset(boost::int64_t offset) const
398400
{
401+
TORRENT_ASSERT_PRECOND(offset >= 0);
402+
TORRENT_ASSERT_PRECOND(offset < m_total_size);
399403
// find the file iterator and file offset
400404
internal_file_entry target;
401405
target.offset = offset;
@@ -425,6 +429,8 @@ namespace libtorrent
425429
, boost::int64_t const offset
426430
, int size) const
427431
{
432+
TORRENT_ASSERT_PRECOND(piece >= 0);
433+
TORRENT_ASSERT_PRECOND(piece < num_pieces());
428434
TORRENT_ASSERT_PRECOND(num_files() > 0);
429435
std::vector<file_slice> ret;
430436

@@ -1067,11 +1073,10 @@ namespace libtorrent
10671073
i = m_files.begin() + cur_index;
10681074
e.size = size;
10691075
e.offset = offset;
1070-
char name[30];
1071-
snprintf(name, sizeof(name), ".pad" TORRENT_SEPARATOR_STR "%d"
1072-
, pad_file_counter);
1073-
std::string path = combine_path(m_name, name);
1074-
e.set_name(path.c_str());
1076+
e.path_index = get_or_add_path(".pad", 4);
1077+
char name[15];
1078+
snprintf(name, sizeof(name), "%d", pad_file_counter);
1079+
e.set_name(name);
10751080
e.pad_file = true;
10761081
offset += size;
10771082
++pad_file_counter;

test/test_file_storage.cpp

+30
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,36 @@ void setup_test_storage(file_storage& st)
7575
TEST_EQUAL(st.num_pieces(), (100000 + 0x3fff) / 0x4000);
7676
}
7777

78+
TORRENT_TEST(coalesce_path)
79+
{
80+
file_storage st;
81+
st.add_file(combine_path("test", "a"), 10000);
82+
TEST_EQUAL(st.paths().size(), 1);
83+
TEST_EQUAL(st.paths()[0], "");
84+
st.add_file(combine_path("test", "b"), 20000);
85+
TEST_EQUAL(st.paths().size(), 1);
86+
TEST_EQUAL(st.paths()[0], "");
87+
st.add_file(combine_path("test", combine_path("c", "a")), 30000);
88+
TEST_EQUAL(st.paths().size(), 2);
89+
TEST_EQUAL(st.paths()[0], "");
90+
TEST_EQUAL(st.paths()[1], "c");
91+
92+
// make sure that two files with the same path shares the path entry
93+
st.add_file(combine_path("test", combine_path("c", "b")), 40000);
94+
TEST_EQUAL(st.paths().size(), 2);
95+
TEST_EQUAL(st.paths()[0], "");
96+
TEST_EQUAL(st.paths()[1], "c");
97+
98+
// cause pad files to be created, to make sure the pad files also share the
99+
// same path entries
100+
st.optimize(0, 1024, true);
101+
102+
TEST_EQUAL(st.paths().size(), 3);
103+
TEST_EQUAL(st.paths()[0], "");
104+
TEST_EQUAL(st.paths()[1], "c");
105+
TEST_EQUAL(st.paths()[2], ".pad");
106+
}
107+
78108
TORRENT_TEST(rename_file)
79109
{
80110
// test rename_file

0 commit comments

Comments
 (0)