| 153 | } |
| 154 | |
| 155 | void BackupSizeCache::compute(u64 id, const std::string& rootPath) |
| 156 | { |
| 157 | // Enumerate the immediate backup folders, summing each subtree (and keeping |
| 158 | // the per-backup totals). walkSize does the recursive walk, honoring the |
| 159 | // pause gate; the mStop check between folders lets a shutdown abort a long |
| 160 | // scan promptly. |
| 161 | Entry entry; |
| 162 | std::string base = rootPath; |
| 163 | if (!base.empty() && base.back() != '/') { |
| 164 | base += "/"; |
| 165 | } |
| 166 | |
| 167 | Directory items(base); |
| 168 | if (items.good()) { |
| 169 | for (size_t i = 0, sz = items.size(); i < sz && !mStop.load(); i++) { |
| 170 | gate(); |
| 171 | const std::string full = base + items.entry(i); |
| 172 | if (items.folder(i)) { |
| 173 | const u64 s = walkSize(full + "/"); |
| 174 | entry.total += s; |
| 175 | entry.perBackup[full] = s; |
| 176 | } |
| 177 | else { |
| 178 | struct stat st; |
| 179 | if (stat(full.c_str(), &st) == 0) { |
| 180 | entry.total += (u64)st.st_size; |
| 181 | } |
| 182 | } |
| 183 | } |
| 184 | } |
| 185 | |
| 186 | std::lock_guard<std::mutex> lock(mMutex); |
| 187 | mPending.erase(id); |
| 188 | // Discard a partial result produced during shutdown, or one invalidated |
| 189 | // while the walk was running. |
| 190 | if (mStop.load() || mDirty.erase(id) != 0) { |
| 191 | return; |
| 192 | } |
| 193 | mCache[id] = std::move(entry); |
| 194 | mGeneration.fetch_add(1); |
| 195 | } |
| 196 | |
| 197 | u64 BackupSizeCache::walkSize(const std::string& path) |
| 198 | { |