refactor: replace tr_torrentFiles() with tr_torrentFileProgress() (#1994)

* refactor: s/tr_torrentFiles/tr_torrentFileProgress

Replace tr_torrentFiles() with a new function, tr_torrentFileProgress().

tr_torrentFiles() heap-allocated an array of progress structs. There is
nothing intrinsic in tr_torrent making batch computation more efficient,
so this PR replaces it with tr_torrentFileProgress(), a per-file variant
that doesn't use the heap.
This commit is contained in:
Charles Kerr 2021-10-21 13:31:03 -05:00 committed by GitHub
parent b0fd4b474a
commit 8cdc2c633e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 32 additions and 103 deletions

View File

@ -131,8 +131,6 @@ struct RefreshData
{
int sort_column_id;
bool resort_needed;
tr_file_stat* refresh_file_stat;
tr_torrent* tor;
};
@ -156,8 +154,9 @@ bool refreshFilesForeach(
auto const* inf = tr_torrentInfo(tor);
int const enabled = inf->files[index].dnd ? 0 : 1;
int const priority = inf->files[index].priority;
uint64_t const have = refresh_data.refresh_file_stat[index].bytesCompleted;
int const prog = size != 0 ? (int)(100.0 * have / size) : 1;
auto const progress = tr_torrentFileProgress(tor, index);
uint64_t const have = progress.bytes_completed;
int const prog = std::clamp(int(100 * progress.progress), 0, 100);
if (priority != old_priority || enabled != old_enabled || have != old_have || prog != old_prog)
{
@ -276,15 +275,9 @@ void FileList::Impl::refresh()
{
Gtk::SortType order;
int sort_column_id;
tr_file_index_t fileCount;
RefreshData refresh_data;
store_->get_sort_column_id(sort_column_id, order);
refresh_data.sort_column_id = sort_column_id;
refresh_data.resort_needed = false;
refresh_data.refresh_file_stat = tr_torrentFiles(tor, &fileCount);
refresh_data.tor = tor;
RefreshData refresh_data{ sort_column_id, false, tor };
gtr_tree_model_foreach_postorder(
store_,
[this, &refresh_data](Gtk::TreeModel::iterator const& iter)
@ -294,8 +287,6 @@ void FileList::Impl::refresh()
{
store_->set_sort_column(sort_column_id, order);
}
tr_torrentFilesFree(refresh_data.refresh_file_stat, fileCount);
}
}

View File

@ -384,38 +384,28 @@ static void addLabels(tr_torrent const* tor, tr_variant* list)
static void addFileStats(tr_torrent const* tor, tr_variant* list)
{
auto n = tr_file_index_t{};
auto* files = tr_torrentFiles(tor, &n);
auto const* const info = tr_torrentInfo(tor);
for (tr_file_index_t i = 0; i < info->fileCount; ++i)
{
tr_file const* file = &info->files[i];
tr_variant* d = tr_variantListAddDict(list, 3);
tr_variantDictAddInt(d, TR_KEY_bytesCompleted, files[i].bytesCompleted);
auto const* const file = &info->files[i];
tr_variant* const d = tr_variantListAddDict(list, 3);
tr_variantDictAddInt(d, TR_KEY_bytesCompleted, tr_torrentFileProgress(tor, i).bytes_completed);
tr_variantDictAddInt(d, TR_KEY_priority, file->priority);
tr_variantDictAddBool(d, TR_KEY_wanted, !file->dnd);
}
tr_torrentFilesFree(files, n);
}
static void addFiles(tr_torrent const* tor, tr_variant* list)
{
auto n = tr_file_index_t{};
auto* const files = tr_torrentFiles(tor, &n);
auto const* const info = tr_torrentInfo(tor);
for (tr_file_index_t i = 0; i < info->fileCount; ++i)
{
tr_file const* file = &info->files[i];
tr_variant* d = tr_variantListAddDict(list, 3);
tr_variantDictAddInt(d, TR_KEY_bytesCompleted, files[i].bytesCompleted);
tr_variantDictAddInt(d, TR_KEY_bytesCompleted, tr_torrentFileProgress(tor, i).bytes_completed);
tr_variantDictAddInt(d, TR_KEY_length, file->length);
tr_variantDictAddStr(d, TR_KEY_name, file->name);
}
tr_torrentFilesFree(files, n);
}
static void addWebseeds(tr_info const* info, tr_variant* webseeds)

View File

@ -1468,35 +1468,20 @@ static uint64_t countFileBytesCompleted(tr_torrent const* tor, tr_file_index_t i
return total;
}
tr_file_stat* tr_torrentFiles(tr_torrent const* tor, tr_file_index_t* fileCount)
tr_file_progress tr_torrentFileProgress(tr_torrent const* torrent, tr_file_index_t file)
{
TR_ASSERT(tr_isTorrent(tor));
TR_ASSERT(tr_isTorrent(torrent));
TR_ASSERT(file < torrent->info.fileCount);
tr_file_index_t const n = tor->info.fileCount;
tr_file_stat* files = tr_new0(tr_file_stat, n);
tr_file_stat* walk = files;
bool const isSeed = tor->completeness == TR_SEED;
tr_file_index_t const total = torrent->info.files[file].length;
for (tr_file_index_t i = 0; i < n; ++i)
if (torrent->completeness == TR_SEED || total == 0)
{
uint64_t const length = tor->info.files[i].length;
uint64_t const b = isSeed ? length : countFileBytesCompleted(tor, i);
walk->bytesCompleted = b;
walk->progress = length > 0 ? (float)b / (float)length : 1.0F;
++walk;
return { total, total, 1.0 };
}
if (fileCount != nullptr)
{
*fileCount = n;
}
return files;
}
void tr_torrentFilesFree(tr_file_stat* files, [[maybe_unused]] tr_file_index_t fileCount)
{
tr_free(files);
auto const have = countFileBytesCompleted(torrent, file);
return { have, total, have >= total ? 1.0 : have / double(total) };
}
/***

View File

@ -1536,15 +1536,14 @@ void tr_torrentTrackersFree(tr_tracker_stat* trackerStats, int trackerCount);
*/
double* tr_torrentWebSpeeds_KBps(tr_torrent const* torrent);
struct tr_file_stat
struct tr_file_progress
{
uint64_t bytesCompleted;
float progress;
uint64_t bytes_completed;
uint64_t bytes_total;
double progress;
};
tr_file_stat* tr_torrentFiles(tr_torrent const* torrent, tr_file_index_t* fileCount);
void tr_torrentFilesFree(tr_file_stat* files, tr_file_index_t fileCount);
tr_file_progress tr_torrentFileProgress(tr_torrent const* torrent, tr_file_index_t file);
/***********************************************************************
* tr_torrentAvailability

View File

@ -213,8 +213,6 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
- (void)refresh
{
[fTorrent updateFileStat];
fOutline.needsDisplay = YES;
}

View File

@ -193,7 +193,6 @@ typedef NS_ENUM(unsigned int, TorrentDeterminationType) {
@property(nonatomic, readonly) NSArray* fileList;
@property(nonatomic, readonly) NSArray* flatFileList;
@property(nonatomic, readonly) NSInteger fileCount;
- (void)updateFileStat;
//methods require fileStats to have been updated recently to be accurate
- (CGFloat)fileProgress:(FileListNode*)node;

View File

@ -158,7 +158,6 @@ bool trashDataFile(char const* filename, tr_error** error)
NSString* fHashString;
tr_file_stat* fFileStat;
NSArray* fFileList;
NSArray* fFlatFileList;
@ -293,11 +292,6 @@ bool trashDataFile(char const* filename, tr_error** error)
- (void)dealloc
{
[NSNotificationCenter.defaultCenter removeObserver:self];
if (fFileStat)
{
tr_torrentFilesFree(fFileStat, self.fileCount);
}
}
- (NSString*)description
@ -1561,16 +1555,6 @@ bool trashDataFile(char const* filename, tr_error** error)
return fInfo->fileCount;
}
- (void)updateFileStat
{
if (fFileStat)
{
tr_torrentFilesFree(fFileStat, self.fileCount);
}
fFileStat = tr_torrentFiles(fHandle, NULL);
}
- (CGFloat)fileProgress:(FileListNode*)node
{
if (self.fileCount == 1 || self.complete)
@ -1578,28 +1562,17 @@ bool trashDataFile(char const* filename, tr_error** error)
return self.progress;
}
if (!fFileStat)
{
[self updateFileStat];
}
// #5501
if (node.size == 0)
{
return 1.0;
}
NSIndexSet* indexSet = node.indexes;
if (indexSet.count == 1)
{
return fFileStat[indexSet.firstIndex].progress;
}
uint64_t have = 0;
NSIndexSet* indexSet = node.indexes;
for (NSInteger index = indexSet.firstIndex; index != NSNotFound; index = [indexSet indexGreaterThanIndex:index])
{
have += fFileStat[index].bytesCompleted;
have += tr_torrentFileProgress(fHandle, index).bytes_completed;
}
return (CGFloat)have / node.size;
@ -1619,14 +1592,10 @@ bool trashDataFile(char const* filename, tr_error** error)
return NO;
}
if (!fFileStat)
{
[self updateFileStat];
}
__block BOOL canChange = NO;
[indexSet enumerateIndexesWithOptions:NSEnumerationConcurrent usingBlock:^(NSUInteger index, BOOL* stop) {
if (fFileStat[index].progress < 1.0)
auto const progress = tr_torrentFileProgress(fHandle, index);
if (progress.bytes_completed < progress.bytes_total)
{
canChange = YES;
*stop = YES;

View File

@ -478,15 +478,15 @@ TEST_F(RenameTest, partialFile)
{
auto constexpr PieceCount = uint32_t{ 33 };
auto constexpr PieceSize = uint32_t{ 32768 };
auto const length = std::array<uint32_t, 3>{ 1048576, 4096, 512 };
auto const total_size = uint64_t(length[0]) + length[1] + length[2];
auto constexpr Length = std::array<uint32_t, 3>{ 1048576, 4096, 512 };
auto constexpr TotalSize = uint64_t(Length[0]) + Length[1] + Length[2];
/***
**** create our test torrent with an incomplete .part file
***/
auto* tor = zeroTorrentInit();
EXPECT_EQ(total_size, tor->info.totalSize);
EXPECT_EQ(TotalSize, tor->info.totalSize);
EXPECT_EQ(PieceSize, tor->info.pieceSize);
EXPECT_EQ(PieceCount, tor->info.pieceCount);
EXPECT_STREQ("files-filled-with-zeroes/1048576", tor->info.files[0].name);
@ -494,13 +494,11 @@ TEST_F(RenameTest, partialFile)
EXPECT_STREQ("files-filled-with-zeroes/512", tor->info.files[2].name);
zeroTorrentPopulate(tor, false);
auto* fst = tr_torrentFiles(tor, nullptr);
EXPECT_EQ(length[0] - PieceSize, fst[0].bytesCompleted);
EXPECT_EQ(length[1], fst[1].bytesCompleted);
EXPECT_EQ(length[2], fst[2].bytesCompleted);
tr_torrentFilesFree(fst, tor->info.fileCount);
EXPECT_EQ(Length[0], tr_torrentFileProgress(tor, 0).bytes_completed + PieceSize);
EXPECT_EQ(Length[1], tr_torrentFileProgress(tor, 1).bytes_completed);
EXPECT_EQ(Length[2], tr_torrentFileProgress(tor, 2).bytes_completed);
auto const* st = tr_torrentStat(tor);
EXPECT_EQ(total_size, st->sizeWhenDone);
EXPECT_EQ(TotalSize, st->sizeWhenDone);
EXPECT_EQ(PieceSize, st->leftUntilDone);
/***