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