244{
247 {
249 }
250
252
253 std::size_t countRecentUpdates = 0;
254 std::size_t countArchivedUpdates = 0;
255
256
257 for (auto const& entry : applied)
259 ++countRecentUpdates;
260 else
261 ++countArchivedUpdates;
262
263
265 for (auto& entry : applied)
266 hashToName.insert(
std::make_pair(entry.second.hash, entry.first));
267
268 std::size_t importedUpdates = 0;
269
271 {
272 auto filePath = sqlFile.first;
273 auto fileState = sqlFile.second;
274
275 LOG_DEBUG(
"sql.updates",
"Checking update \"{}\"...", filePath.filename().generic_string());
276
277 AppliedFileStorage::const_iterator iter = applied.find(filePath.filename().string());
278 if (iter != applied.end())
279 {
280
281 if (!redundancyChecks)
282 {
283 LOG_DEBUG(
"sql.updates",
">> Update is already applied, skipping redundancy checks.");
284 applied.erase(iter);
285 return;
286 }
287
288
289 if (!archivedRedundancy && (iter->second.state ==
ARCHIVED) && (sqlFile.second ==
ARCHIVED))
290 {
291 LOG_DEBUG(
"sql.updates",
">> Update is archived and marked as archived in database, skipping redundancy checks.");
292 applied.erase(iter);
293 return;
294 }
295 }
296
298
300
301
302 if (iter == applied.end())
303 {
304
305 HashToFileNameStorage::const_iterator const hashIter = hashToName.find(hash);
306 if (hashIter != hashToName.end())
307 {
308
309 LocaleFileStorage::const_iterator localeIter;
310
311
312 for (localeIter = available.begin(); (localeIter != available.end()) &&
313 (localeIter->first.filename().string() != hashIter->second); ++localeIter);
314
315
316 if (localeIter != available.end())
317 {
318 LOG_WARN(
"sql.updates",
">> It seems like the update \"{}\" \'{}\' was renamed, but the old file is still there! " \
319 "Treating it as a new file! (It is probably an unmodified copy of the file \"{}\")",
320 filePath.filename().string(), hash.substr(0, 7),
321 localeIter->first.filename().string());
322 }
323 else
324 {
325 LOG_INFO(
"sql.updates",
">> Renaming update \"{}\" to \"{}\" \'{}\'.",
326 hashIter->second, filePath.filename().string(), hash.substr(0, 7));
327
328 RenameEntry(hashIter->second, filePath.filename().string());
329 applied.erase(hashIter->second);
330 return;
331 }
332 }
333
334 else
335 {
336 LOG_INFO(
"sql.updates",
">> Applying update \"{}\" \'{}\'...",
337 filePath.filename().string(), hash.substr(0, 7));
338 }
339 }
340
341 else if (allowRehash && iter->second.hash.empty())
342 {
344
345 LOG_INFO(
"sql.updates",
">> Re-hashing update \"{}\" \'{}\'...", filePath.filename().string(),
346 hash.substr(0, 7));
347 }
348 else
349 {
350
351 if (iter->second.hash != hash)
352 {
353 LOG_INFO(
"sql.updates",
">> Reapplying update \"{}\" \'{}\' -> \'{}\' (it changed)...", filePath.filename().string(),
354 iter->second.hash.substr(0, 7), hash.substr(0, 7));
355 }
356 else
357 {
358
359 if (iter->second.state != fileState)
360 {
361 LOG_DEBUG(
"sql.updates",
">> Updating the state of \"{}\" to \'{}\'...",
363
364 UpdateState(filePath.filename().string(), fileState);
365 }
366
367 LOG_DEBUG(
"sql.updates",
">> Update is already applied and matches the hash \'{}\'.", hash.substr(0, 7));
368
369 applied.erase(iter);
370 return;
371 }
372 }
373
375 AppliedFileEntry const file = { filePath.filename().string(), hash, fileState, 0 };
376
377 switch (mode)
378 {
380 speed =
Apply(filePath);
381 [[fallthrough]];
384 break;
385 }
386
387 if (iter != applied.end())
388 applied.erase(iter);
389
391 ++importedUpdates;
392 };
393
394
395 for (auto const& availableQuery : available)
396 {
397 if (availableQuery.second !=
PENDING && availableQuery.second !=
CUSTOM && availableQuery.second !=
MODULE)
398 ApplyUpdateFile(availableQuery);
399 }
400
401
402 for (auto const& availableQuery : available)
403 {
404 if (availableQuery.second ==
PENDING || availableQuery.second ==
CUSTOM || availableQuery.second ==
MODULE)
405 ApplyUpdateFile(availableQuery);
406 }
407
408
410 {
411 bool const doCleanup = (cleanDeadReferencesMaxCount < 0) || (applied.size() <= static_cast<size_t>(cleanDeadReferencesMaxCount));
412
414 for (auto const& entry : applied)
415 {
416 if (entry.second.state !=
MODULE)
417 {
419 ">> The file \'{}\' was applied to the database, but is missing in"
420 " your update directory now!",
421 entry.first);
422
423 if (doCleanup)
424 {
425 LOG_INFO(
"sql.updates",
"Deleting orphaned entry \'{}\'...", entry.first);
426 toCleanup.insert(entry);
427 }
428 }
429 }
430
431 if (!toCleanup.empty())
432 {
433 if (doCleanup)
435 else
436 {
438 "Cleanup is disabled! There were {} dirty files applied to your database, "
439 "but they are now missing in your source directory!",
440 toCleanup.size());
441 }
442 }
443 }
444
445 return UpdateResult(importedUpdates, countRecentUpdates, countArchivedUpdates);
446}
#define LOG_INFO(filterType__,...)
Definition Log.h:153
#define LOG_ERROR(filterType__,...)
Definition Log.h:145
#define LOG_DEBUG(filterType__,...)
Definition Log.h:157
std::string ByteArrayToHexStr(Container const &c, bool reverse=false)
Definition Util.h:372
static Digest GetDigestOf(uint8 const *data, std::size_t len)
Definition CryptoHash.h:48
uint32 Apply(Path const &path) const
Definition UpdateFetcher.cpp:448
LocaleFileStorage GetFileList() const
Definition UpdateFetcher.cpp:64
void UpdateState(std::string const &name, State const state) const
Definition UpdateFetcher.cpp:513
UpdateMode
Definition UpdateFetcher.h:66
std::string ReadSQLUpdate(Path const &file) const
Definition UpdateFetcher.cpp:216
void UpdateEntry(AppliedFileEntry const &entry, uint32 const speed=0) const
Definition UpdateFetcher.cpp:462
void RenameEntry(std::string const &from, std::string const &to) const
Definition UpdateFetcher.cpp:471
std::unordered_map< std::string, std::string > HashToFileNameStorage
Definition UpdateFetcher.h:139
AppliedFileStorage ReceiveAppliedFiles() const
Definition UpdateFetcher.cpp:193
void CleanUp(AppliedFileStorage const &storage) const
Definition UpdateFetcher.cpp:490
Definition UpdateFetcher.h:30