-
Notifications
You must be signed in to change notification settings - Fork 38
implement time-based upload stats (V2) with configurable retention and auto-cleanup #262
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -80,6 +80,7 @@ p3FileDatabase::p3FileDatabase(p3ServiceControl *mpeers) | |
| mLastDataRecvTS = 0 ; | ||
| mTrustFriendNodesForBannedFiles = TRUST_FRIEND_NODES_FOR_BANNED_FILES_DEFAULT; | ||
| mLastPrimaryBanListChangeTimeStamp = 0; | ||
| mUploadStatsRetentionDays = 0; | ||
|
|
||
| // This is for the transmission of data | ||
|
|
||
|
|
@@ -197,6 +198,7 @@ int p3FileDatabase::tick() | |
| if(mLastCleanupTime + 5 < now) | ||
| { | ||
| cleanup(); | ||
| cleanupUploadStats(mUploadStatsRetentionDays); | ||
| mLastCleanupTime = now ; | ||
| } | ||
|
|
||
|
|
@@ -379,12 +381,12 @@ cleanup = true; | |
|
|
||
| { | ||
| RS_STACK_MUTEX(mFLSMtx) ; | ||
| RsFileListsUploadStatsItem *item = nullptr; | ||
| RsFileListsUploadStatsItemV2 *item = nullptr; | ||
|
|
||
| for(auto it(mCumulativeUploaded.begin());it!=mCumulativeUploaded.end();++it) | ||
| { | ||
| if(item == nullptr) | ||
| item = new RsFileListsUploadStatsItem ; | ||
| item = new RsFileListsUploadStatsItemV2 ; | ||
|
|
||
| item->hash_stats.insert(*it); | ||
|
|
||
|
|
@@ -497,6 +499,15 @@ cleanup = true; | |
|
|
||
| kv.key = IGNORE_LIST_FLAGS_SS; kv.value = s; rskv->tlvkvs.pairs.push_back(kv); | ||
| } | ||
| { | ||
| std::string s; | ||
| rs_sprintf(s, "%d", mUploadStatsRetentionDays); | ||
|
|
||
| RsTlvKeyValue kv; | ||
| kv.key = UPLOAD_STATS_RETENTION_DAYS_SS; | ||
| kv.value = s; | ||
| rskv->tlvkvs.pairs.push_back(kv); | ||
| } | ||
|
|
||
| /* Add KeyValue to saveList */ | ||
| sList.push_back(rskv); | ||
|
|
@@ -618,6 +629,12 @@ bool p3FileDatabase::loadList(std::list<RsItem *>& load) | |
| if(sscanf(kit->value.c_str(),"%d",&t) == 1) | ||
| max_share_depth = (uint32_t)t ; | ||
| } | ||
| else if(kit->key == UPLOAD_STATS_RETENTION_DAYS_SS) | ||
| { | ||
| int t=0; | ||
| if(sscanf(kit->value.c_str(),"%d",&t) == 1) | ||
| mUploadStatsRetentionDays = t; | ||
| } | ||
|
|
||
| delete *it ; | ||
| continue ; | ||
|
|
@@ -654,7 +671,23 @@ bool p3FileDatabase::loadList(std::list<RsItem *>& load) | |
|
|
||
| if(fu) | ||
| { | ||
| mCumulativeUploaded.insert(fu->hash_stats.begin(), fu->hash_stats.end()) ; | ||
| // Migration V1 -> V2: Set timestamp to now | ||
| uint64_t now = time(NULL); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use rstime_t which is guarantied to be uint64_t on all platforms. |
||
| RsDbg() << "UPLOADSTATS Migrating V1 stats (count: " << fu->hash_stats.size() << ") to V2"; | ||
| for(auto const& [hash, bytes] : fu->hash_stats) | ||
| { | ||
| TimeBasedUploadStat& stat = mCumulativeUploaded[hash]; | ||
| stat.total_bytes = bytes; | ||
| stat.last_upload_ts = now; | ||
| } | ||
| } | ||
|
|
||
| RsFileListsUploadStatsItemV2 *fu2 = dynamic_cast<RsFileListsUploadStatsItemV2*>(*it) ; | ||
|
|
||
| if(fu2) | ||
| { | ||
| RsDbg() << "UPLOADSTATS Loading V2 stats (count: " << fu2->hash_stats.size() << ")"; | ||
| mCumulativeUploaded.insert(fu2->hash_stats.begin(), fu2->hash_stats.end()) ; | ||
| } | ||
|
|
||
| delete *it ; | ||
|
|
@@ -1056,7 +1089,7 @@ uint64_t p3FileDatabase::getCumulativeUpload(const RsFileHash& hash) const | |
| RS_STACK_MUTEX(mFLSMtx); | ||
| auto it = mCumulativeUploaded.find(hash); | ||
| if (it != mCumulativeUploaded.end()) | ||
| return it->second; | ||
| return it->second.total_bytes; | ||
| return 0; | ||
| } | ||
|
|
||
|
|
@@ -1065,7 +1098,7 @@ uint64_t p3FileDatabase::getCumulativeUploadAll() const | |
| RS_STACK_MUTEX(mFLSMtx); | ||
| uint64_t total = 0; | ||
| for (auto it = mCumulativeUploaded.begin(); it != mCumulativeUploaded.end(); ++it) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks costly. Depending on whether this method is called many times or not, it may slow down the UI. It's probably better to keep this as a value that is updated in cleanUploadStats(), which you simply return in this method. I don't think we need accuracy beyond 5 secs here anyway. |
||
| total += it->second; | ||
| total += it->second.total_bytes; | ||
| return total; | ||
| } | ||
|
|
||
|
|
@@ -1078,15 +1111,71 @@ uint64_t p3FileDatabase::getCumulativeUploadNum() const | |
| void p3FileDatabase::addUploadStats(const RsFileHash& hash, uint64_t size) | ||
| { | ||
| RS_STACK_MUTEX(mFLSMtx); | ||
| mCumulativeUploaded[hash] += size; | ||
| TimeBasedUploadStat& stat = mCumulativeUploaded[hash]; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Be careful of initialization here! See comment about the missing constructor of TimeBasedUploadStat. |
||
| stat.total_bytes += size; | ||
| stat.last_upload_ts = time(NULL); | ||
|
|
||
| // RsDbg() << "UPLOADSTATS add stats: " << hash << " + " << size << " bytes. Total: " << stat.total_bytes << " ts: " << stat.last_upload_ts; | ||
| IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_OFTEN); | ||
| } | ||
|
|
||
| void p3FileDatabase::clearUploadStats() | ||
| { | ||
| RS_STACK_MUTEX(mFLSMtx); | ||
| RsDbg() << "UPLOADSTATS clearing all stats"; | ||
| mCumulativeUploaded.clear(); | ||
| } | ||
|
|
||
| void p3FileDatabase::cleanupUploadStats(int days) | ||
| { | ||
| if (days <= 0) return; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function should also probably check that the files are still shared. This may get costly, so see whether that particular check can be done less often and where. |
||
|
|
||
| RS_STACK_MUTEX(mFLSMtx); | ||
| time_t cutoff = time(NULL) - (days * 24 * 3600); | ||
| uint32_t removed_count = 0; | ||
|
|
||
| // RsDbg() << "UPLOADSTATS cleanup stats older than " << days << " days (cutoff: " << cutoff << ")"; | ||
|
|
||
| for (auto it = mCumulativeUploaded.begin(); it != mCumulativeUploaded.end(); ) | ||
| { | ||
| if (it->second.last_upload_ts < (uint64_t)cutoff) | ||
| { | ||
| RsDbg() << "UPLOADSTATS removing expired stat: " << it->first << " (ts: " << it->second.last_upload_ts << ")"; | ||
| it = mCumulativeUploaded.erase(it); | ||
| removed_count++; | ||
| } | ||
| else | ||
| { | ||
| ++it; | ||
| } | ||
| } | ||
| if (removed_count > 0) | ||
| { | ||
| RsDbg() << "UPLOAD cleanup removed " << removed_count << " entries."; | ||
| IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_OFTEN); | ||
| } | ||
| } | ||
|
|
||
| void p3FileDatabase::setUploadStatsRetentionDays(int days) | ||
| { | ||
| if (mUploadStatsRetentionDays != days) | ||
| { | ||
| mUploadStatsRetentionDays = days; | ||
| RsDbg() << "UPLOADSTATS setting retention days to: " << days; | ||
| IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_OFTEN); | ||
|
|
||
| // Trigger cleanup immediately if days > 0 | ||
| if (days > 0) | ||
| { | ||
| cleanupUploadStats(days); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| int p3FileDatabase::getUploadStatsRetentionDays() const | ||
| { | ||
| return mUploadStatsRetentionDays; | ||
| } | ||
| bool p3FileDatabase::removeExtraFile(const RsFileHash& hash) | ||
| { | ||
| bool ret = false; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -41,6 +41,7 @@ const uint8_t RS_PKT_SUBTYPE_FILELISTS_CONFIG_ITEM = 0x03; | |
| const uint8_t RS_PKT_SUBTYPE_FILELISTS_BANNED_HASHES_ITEM = 0x04; | ||
| const uint8_t RS_PKT_SUBTYPE_FILELISTS_BANNED_HASHES_CONFIG_ITEM = 0x05; | ||
| const uint8_t RS_PKT_SUBTYPE_FILELISTS_UPLOAD_STATS_ITEM = 0x06; | ||
| const uint8_t RS_PKT_SUBTYPE_FILELISTS_UPLOAD_STATS_ITEM_V2 = 0x07; | ||
|
|
||
| /*! | ||
| * Base class for filelist sync items | ||
|
|
@@ -139,6 +140,25 @@ class RsFileListsUploadStatsItem: public RsFileListsItem | |
| std::map<RsFileHash, uint64_t> hash_stats; | ||
| }; | ||
|
|
||
| struct TimeBasedUploadStat | ||
| { | ||
| uint64_t last_upload_ts; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you need a constructor in order to ensure that these values are 0 by default, because they are not initialized when populating the map that contains the hash/values. |
||
| uint64_t total_bytes; | ||
|
|
||
| bool operator==(const TimeBasedUploadStat& r) const { return last_upload_ts == r.last_upload_ts && total_bytes == r.total_bytes; } | ||
| }; | ||
|
|
||
| class RsFileListsUploadStatsItemV2: public RsFileListsItem | ||
| { | ||
| public: | ||
| RsFileListsUploadStatsItemV2() : RsFileListsItem(RS_PKT_SUBTYPE_FILELISTS_UPLOAD_STATS_ITEM_V2){} | ||
|
|
||
| virtual void clear() { hash_stats.clear(); } | ||
| virtual void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx); | ||
|
|
||
| std::map<RsFileHash, TimeBasedUploadStat> hash_stats; | ||
| }; | ||
|
|
||
| class RsFileListsSerialiser : public RsServiceSerializer | ||
| { | ||
| public: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Plz add a date here because this item is deprecated, so that we can remove the code a while when it's not used anymore.
Another option is to completely ignore these "old" items, since upload stats have started very recently anyway.