Пример #1
0
        private void RunConsistencyCheck()
        {
            Printer.PrintMessage(" - Upgrading database - running full consistency check.");
            var objNames = Table<ObjectName>().ToList();
            Dictionary<long, long> nameMapping = new Dictionary<long, long>();
            Dictionary<string, long> nameIndexes = new Dictionary<string, long>();
            DropTable<ObjectName>();
            DropTable<RecordRef>();
            CreateTable<ObjectName>();
            int duplicateObjs = 0;
            foreach (var x in objNames)
            {
                if (nameIndexes.ContainsKey(x.CanonicalName))
                {
                    nameMapping[x.NameId] = nameIndexes[x.CanonicalName];
                    duplicateObjs++;
                }
                else
                {
                    ObjectName oname = new ObjectName() { CanonicalName = x.CanonicalName };
                    Insert(oname);
                    nameMapping[x.NameId] = oname.NameId;
                    nameIndexes[x.CanonicalName] = oname.NameId;
                }
            }
            foreach (var x in Table<Record>().ToList())
            {
                x.CanonicalNameId = nameMapping[x.CanonicalNameId];
                Update(x);
            }
            Printer.PrintMessage(" - Cleaned {0} duplicate canonical names.", duplicateObjs);
            CreateTable<RecordRef>();
            Dictionary<Tuple<string, long, DateTime>, Record> records = new Dictionary<Tuple<string, long, DateTime>, Record>();
            foreach (var x in Table<Objects.Record>().ToList())
            {
                var key = new Tuple<string, long, DateTime>(x.UniqueIdentifier, x.CanonicalNameId, x.ModificationTime);
                if (records.ContainsKey(key))
                {
                    var other = records[key];
                    Printer.PrintDiagnostics("Found duplicate records {0} ==> {1}", x.Id, other.Id);
                    Printer.PrintDiagnostics(" - UID: {0}", x.UniqueIdentifier);
                    Printer.PrintDiagnostics(" - Time: {0}", x.ModificationTime);
                    Printer.PrintDiagnostics(" - Name: {0}", Get<ObjectName>(x.CanonicalNameId).CanonicalName);

                    int updates = 0;
                    foreach (var s in Table<Alteration>().Where(z => z.PriorRecord == x.Id || z.NewRecord == x.Id))
                    {
                        if (s.NewRecord.HasValue && s.NewRecord.Value == x.Id)
                            s.NewRecord = other.Id;
                        if (s.PriorRecord.HasValue && s.PriorRecord.Value == x.Id)
                            s.PriorRecord = other.Id;
                        Update(s);
                        updates++;
                    }
                    Delete(x);
                    Printer.PrintDiagnostics("Deleted record and updated {0} links.", updates);
                }
                else
                    records[key] = x;
            }
            foreach (var x in Table<Objects.Version>().ToList())
            {
                x.Snapshot = null;
                Update(x);
                var alterations = Table<Objects.Alteration>().Where(z => z.Owner == x.AlterationList);
                HashSet<long> moveAdds = new HashSet<long>();
                HashSet<long> moveDeletes = new HashSet<long>();
                foreach (var s in alterations)
                {
                    if (s.Type == AlterationType.Move)
                    {
                        moveAdds.Add(s.NewRecord.Value);
                        moveDeletes.Add(s.PriorRecord.Value);
                    }
                }
                foreach (var s in alterations)
                {
                    if (s.Type == AlterationType.Add && moveAdds.Contains(s.NewRecord.Value))
                    {
                        Delete(s);
                        Printer.PrintDiagnostics("Cleaned up extra add in v{0} for \"{1}\"", x.ShortName, Get<ObjectName>(Get<Record>(s.NewRecord.Value).CanonicalNameId).CanonicalName);
                    }
                    if (s.Type == AlterationType.Delete && moveDeletes.Contains(s.PriorRecord.Value))
                    {
                        Delete(s);
                        Printer.PrintDiagnostics("Cleaned up extra delete in v{0} for \"{1}\"", x.ShortName, Get<ObjectName>(Get<Record>(s.PriorRecord.Value).CanonicalNameId).CanonicalName);
                    }
                }
            }
        }
Пример #2
0
        private WorkspaceDB(string path, SQLite.SQLiteOpenFlags flags, LocalDB localDB) : base(path, flags)
        {
            Printer.PrintDiagnostics("Metadata DB Open.");
            EnableWAL = true;
            LocalDatabase = localDB;
            
            CreateTable<Objects.FormatInfo>();
            if (flags.HasFlag(SQLite.SQLiteOpenFlags.Create))
            {
                ExecuteDirect("PRAGMA main.page_size = 4096;");
                ExecuteDirect("PRAGMA main.cache_size = 10240;");
                ExecuteDirect("PRAGMA temp_store = MEMORY;");
                EnableWAL = true;
                PrepareTables();
                return;
            }

            if (!ValidForUpgrade)
                return;

            if (Format.InternalFormat < InternalDBVersion)
            {
                try
                {
                    var fmt = Format;
					int priorFormat = fmt.InternalFormat;
                    if (priorFormat < 17)
                    {
                        ExecuteDirect("PRAGMA main.page_size = 4096;");
                        ExecuteDirect("PRAGMA main.cache_size = 10240;");
                        ExecuteDirect("PRAGMA temp_store = MEMORY;");
                        EnableWAL = false;
                        ExecuteDirect("VACUUM");
                        EnableWAL = true;
                    }
                    BeginExclusive(true);
                    if (priorFormat <= 12)
                    {
                        var info = GetTableInfo("ObjectName");
                        if (info.Where(x => x.Name == "NameId").Count() == 0)
                        {
                            var objNames = Query<ObjectNameOld>("SELECT * FROM ObjectName").ToList();
                            Dictionary<long, long> nameMapping = new Dictionary<long, long>();
                            Dictionary<string, long> nameIndexes = new Dictionary<string, long>();
                            DropTable<ObjectName>();
                            Commit();
                            BeginExclusive();
                            CreateTable<ObjectName>();
                            foreach (var x in objNames)
                            {
                                if (nameIndexes.ContainsKey(x.CanonicalName))
                                {
                                    nameMapping[x.Id] = nameIndexes[x.CanonicalName];
                                }
                                else
                                {
                                    ObjectName oname = new ObjectName() { CanonicalName = x.CanonicalName };
                                    Insert(oname);
                                    nameMapping[x.Id] = oname.NameId;
                                    nameIndexes[x.CanonicalName] = oname.NameId;
                                }
                            }
                            foreach (var x in Table<Record>().ToList())
                            {
                                x.CanonicalNameId = nameMapping[x.CanonicalNameId];
                                Update(x);
                            }
                            Commit();
                        }
                    }
                    PrepareTables();
                    Printer.PrintMessage("Updating workspace database version from v{0} to v{1}", Format.InternalFormat, InternalDBVersion);

                    if (priorFormat < 28)
                    {
                        var tips = Query<BranchJournal>("SELECT * FROM BranchJournal WHERE NOT EXISTS (SELECT * FROM BranchJournalLink WHERE Parent = BranchJournal.ID)").ToList();
                        if (tips.Count > 1)
                            Printer.PrintError("#e#Database update encountered an error - multiple possible tips for branch journal data found. Selecting final revision.");
                        if (tips.Count != 0)
                            BranchJournalTip = tips[tips.Count - 1].ID;
                    }
                    if (priorFormat < 14)
                    {
                        ExecuteDirect("DROP TABLE RecordIndex;");
                    }
                    if (priorFormat < 32)
                    {
                        int count = 0;
                        foreach (var x in Table<Objects.Version>())
                        {
                            if (x.Message != null && x.Message.StartsWith("Automatic merge of"))
                            {
                                var mergeInfos = Table<MergeInfo>().Where(y => y.DestinationVersion == x.ID).ToList();
                                if (mergeInfos.Count == 1)
                                {
                                    mergeInfos[0].Type = MergeType.Automatic;
                                    Update(mergeInfos[0]);
                                    count++;
                                }
                            }
                        }
                        Printer.PrintMessage("Updated #b#{0}## merge info records.", count);
                    }
                    if (priorFormat < 31)
                    {
                        Dictionary<long, Record> recordMap = new Dictionary<long, Record>();
                        foreach (var x in Table<Record>().ToList())
                            recordMap[x.Id] = x;

                        foreach (var x in Table<Record>().ToList())
                        {
                            if (x.Parent.HasValue && !recordMap.ContainsKey(x.Parent.Value))
                            {
                                x.Parent = null;
                                Update(x);
                            }
                        }
                    }
                    if (priorFormat < 30)
                    {
                        RunConsistencyCheck();
                    }
                    if (priorFormat < 30)
                    {
                        foreach (var x in Table<Objects.Version>().ToList())
                        {
                            x.Snapshot = null;
                            Update(x);
                            var alterations = Table<Objects.Alteration>().Where(z => z.Owner == x.AlterationList);
                            Dictionary<long, bool> moveDeletes = new Dictionary<long, bool>();
                            HashSet<long> deletions = new HashSet<long>();
                            int counter = 0;
                            foreach (var s in alterations)
                            {
                                if (s.Type == AlterationType.Move)
                                {
                                    if (moveDeletes.ContainsKey(s.PriorRecord.Value))
                                        moveDeletes[s.PriorRecord.Value] = false;
                                    else
                                        moveDeletes[s.PriorRecord.Value] = true;
                                }
                            }
                            foreach (var s in alterations)
                            {
                                if (s.Type == AlterationType.Move)
                                {
                                    if (moveDeletes[s.PriorRecord.Value] == false)
                                    {
                                        s.Type = AlterationType.Copy;
                                        Update(s);
                                        deletions.Add(s.PriorRecord.Value);
                                        counter++;
                                    }
                                }
                            }
                            foreach (var s in deletions)
                            {
                                Alteration alt = new Alteration() { PriorRecord = s, Type = AlterationType.Delete, Owner = x.AlterationList };
                                Insert(alt);
                            }
                            if (counter > 0)
                                Printer.PrintDiagnostics("Version {0} had {1} multiple-moves that have been fixed.", x.ShortName, counter);
                        }
                    }
                    if (priorFormat < 30)
                    {
                        foreach (var x in Table<Objects.Version>().ToList())
                        {
                            x.Snapshot = null;
                            Update(x);
                            var alterations = Table<Objects.Alteration>().Where(z => z.Owner == x.AlterationList);
                            HashSet<Tuple<AlterationType, long?, long?>> duplicateAlterations = new HashSet<Tuple<AlterationType, long?, long?>>();
                            int counter = 0;
                            foreach (var s in alterations)
                            {
                                var key = new Tuple<AlterationType, long?, long?>(s.Type, s.NewRecord, s.PriorRecord);
                                if (duplicateAlterations.Contains(key))
                                {
                                    Delete(s);
                                    counter++;
                                }
                                else
                                    duplicateAlterations.Add(key);
                            }
                            if (counter > 0)
                                Printer.PrintDiagnostics("Version {0} had {1} duplicated alterations that have been fixed.", x.ShortName, counter);
                        }
                    }
                    else if (priorFormat == 7)
                    {
                        Printer.PrintMessage(" - Upgrading database - adding branch root version.");
                        foreach (var x in Table<Objects.Branch>().ToList())
                        {
                            var allVersions = Table<Objects.Version>().Where(y => y.Branch == x.ID);
                            Guid? rootVersion = null;
                            foreach (var y in allVersions)
                            {
                                if (y.Parent.HasValue)
                                {
                                    Objects.Version parent = Get<Objects.Version>(y.Parent);
                                    if (parent.Branch != x.ID)
                                    {
                                        rootVersion = parent.ID;
                                        break;
                                    }
                                }
                            }
                            x.RootVersion = rootVersion;
                            Update(x);
                        }
                    }
                    DropTable<Objects.FormatInfo>();
                    fmt.InternalFormat = InternalDBVersion;
                    CreateTable<Objects.FormatInfo>();
                    Insert(fmt);

                    Commit();

                    ExecuteDirect("VACUUM");
                }
                catch (Exception e)
                {
                    Rollback();
                    Printer.PrintError("Couldn't update DB: {0}", e.ToString());
                }
                PrepareTables();
            }
        }