示例#1
0
        void CleanUp(AppliedFileStorage storage)
        {
            if (storage.Count == 0)
            {
                return;
            }

            using (var update = ZString.CreateStringBuilder(true))
            {
                var remaining = storage.Count;

                update.Append("DELETE FROM `updates` WHERE `name` IN(");

                foreach (var item in storage)
                {
                    update.Append("\"");
                    update.Append(item.Key);
                    update.Append("\"");

                    if ((--remaining) > 0)
                    {
                        update.Append(", ");
                    }
                }

                update.Append(")");

                // Update database
                _apply(update.ToString());
            }
        }
示例#2
0
        public UpdateResult Update(bool redundancyChecks, bool allowRehash, bool archivedRedundancy, int cleanDeadReferencesMaxCount)
        {
            var available = GetFileList();
            AppliedFileStorage applied = ReceiveAppliedFiles();

            int countRecentUpdates   = 0;
            int countArchivedUpdates = 0;

            // Count updates
            foreach (var entry in applied.Values)
            {
                if (entry.State == State.RELEASED)
                {
                    ++countRecentUpdates;
                }
                else
                {
                    ++countArchivedUpdates;
                }
            }

            // Fill hash to name cache
            HashToFileNameStorage hashToName = new HashToFileNameStorage();

            foreach (var entry in applied)
            {
                hashToName[entry.Value.Hash] = entry.Key;
            }

            int importedUpdates = 0;

            foreach (var availableQuery in available)
            {
                var filename = availableQuery.GetFileName();
                FEL_LOG_DEBUG("sql.updates", "Checking update \"{0}\"...", filename);

                AppliedFileEntry appliedFile;
                bool             filenameApplied = applied.TryGetValue(filename, out appliedFile);

                if (filenameApplied)
                {
                    // If redundancy is disabled, skip it, because the update is already applied.
                    if (!redundancyChecks)
                    {
                        FEL_LOG_DEBUG("sql.updates", ">> Update is already applied, skipping redundancy checks.");
                        applied.Remove(filename);
                        continue;
                    }

                    // If the update is in an archived directory and is marked as archived in our database, skip redundancy checks (archived updates never change).
                    if (!archivedRedundancy && (appliedFile.State == State.ARCHIVED) && (availableQuery.State == State.ARCHIVED))
                    {
                        FEL_LOG_DEBUG("sql.updates", ">> Update is archived and marked as archived in database, skipping redundancy checks.");
                        applied.Remove(filename);
                        continue;
                    }
                }

                // Calculate a Sha1 hash based on query content.
                string hash = ByteArrayToHexStr(DigestSHA1(ReadSQLUpdate(availableQuery.FilePath)));

                UpdateMode mode = UpdateMode.MODE_APPLY;

                // Update is not in our applied list
                if (!filenameApplied)
                {
                    // Catch renames (different filename, but same hash)
                    if (hashToName.TryGetValue(hash, out filename))
                    {
                        // Check if the original file was removed. If not, we've got a problem.
                        LocaleFileEntry?renameFile = null;
                        foreach (var item in available)
                        {
                            if (item.GetFileName() == filename)
                            {
                                renameFile = item;
                                break;
                            }
                        }

                        // Conflict!
                        if (renameFile != null)
                        {
                            FEL_LOG_WARN("sql.updates", ">> It seems like the update \"{0}\" \'{1}\' was renamed, but the old file is still there! Treating it as a new file! (It is probably an unmodified copy of the file \"{2}\")",
                                         availableQuery.GetFileName(), hash.Substring(0, 7), renameFile.Value.GetFileName());
                        }
                        // It is safe to treat the file as renamed here
                        else
                        {
                            FEL_LOG_INFO("sql.updates", ">> Renaming update \"{0}\" to \"{1}\" \'{2}\'.", filename, availableQuery.GetFileName(), hash.Substring(0, 7));

                            RenameEntry(filename, availableQuery.GetFileName());
                            applied.Remove(filename);
                            continue;
                        }
                    }
                    // Apply the update if it was never seen before.
                    else
                    {
                        FEL_LOG_INFO("sql.updates", ">> Applying update \"{0}\" \'{1}\'...", availableQuery.GetFileName(), hash.Substring(0, 7));
                    }
                }
                // Rehash the update entry if it exists in our database with an empty hash.
                else if (allowRehash && string.IsNullOrEmpty(appliedFile.Hash))
                {
                    mode = UpdateMode.MODE_REHASH;

                    FEL_LOG_INFO("sql.updates", ">> Re-hashing update \"{0}\" \'{1}\'...", availableQuery.GetFileName(), hash.Substring(0, 7));
                }
                else
                {
                    // If the hash of the files differs from the one stored in our database, reapply the update (because it changed).
                    if (appliedFile.Hash != hash)
                    {
                        FEL_LOG_INFO("sql.updates", ">> Reapplying update \"{0}\" \'{1}\' -> \'{2}\' (it changed)...", availableQuery.GetFileName(),
                                     appliedFile.Hash.Substring(0, 7), hash.Substring(0, 7));
                    }
                    else
                    {
                        // If the file wasn't changed and just moved, update its state (if necessary).
                        if (appliedFile.State != availableQuery.State)
                        {
                            FEL_LOG_DEBUG("sql.updates", ">> Updating the state of \"{0}\" to \'{1}\'...", availableQuery.GetFileName(), availableQuery.State);

                            UpdateState(availableQuery.GetFileName(), availableQuery.State);
                        }

                        FEL_LOG_DEBUG("sql.updates", ">> Update is already applied and matches the hash \'{0}\'.", hash.Substring(0, 7));

                        applied.Remove(appliedFile.Name);
                        continue;
                    }
                }

                uint speed = 0;
                var  file  = new AppliedFileEntry(availableQuery.GetFileName(), hash, availableQuery.State, 0);

                switch (mode)
                {
                case UpdateMode.MODE_APPLY:
                    speed = Apply(availableQuery.FilePath);
                    goto case UpdateMode.MODE_REHASH;

                case UpdateMode.MODE_REHASH:
                    UpdateEntry(ref file, speed);
                    break;
                }

                if (filenameApplied)
                {
                    applied.Remove(appliedFile.Name);
                }

                if (mode == UpdateMode.MODE_APPLY)
                {
                    ++importedUpdates;
                }
            }

            // Cleanup up orphaned entries (if enabled)
            if (applied.Count > 0)
            {
                bool doCleanup = (cleanDeadReferencesMaxCount < 0) || (applied.Count <= cleanDeadReferencesMaxCount);

                foreach (var entry in applied)
                {
                    FEL_LOG_WARN("sql.updates", ">> The file \'{0}\' was applied to the database, but is missing in your update directory now!", entry.Key);

                    if (doCleanup)
                    {
                        FEL_LOG_INFO("sql.updates", "Deleting orphaned entry \'{0}\'...", entry.Key);
                    }
                }

                if (doCleanup)
                {
                    CleanUp(applied);
                }
                else
                {
                    FEL_LOG_ERROR("sql.updates", "Cleanup is disabled! There were {0} dirty files applied to your database, but they are now missing in your source directory!", applied.Count);
                }
            }

            return(new UpdateResult(importedUpdates, countRecentUpdates, countArchivedUpdates));
        }