Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono-addins.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'Mono.Addins/Mono.Addins.Database/AddinDatabase.cs')
-rw-r--r--Mono.Addins/Mono.Addins.Database/AddinDatabase.cs530
1 files changed, 290 insertions, 240 deletions
diff --git a/Mono.Addins/Mono.Addins.Database/AddinDatabase.cs b/Mono.Addins/Mono.Addins.Database/AddinDatabase.cs
index 34f931f..842c12b 100644
--- a/Mono.Addins/Mono.Addins.Database/AddinDatabase.cs
+++ b/Mono.Addins/Mono.Addins.Database/AddinDatabase.cs
@@ -28,40 +28,43 @@
using System;
-using System.Threading;
using System.Collections;
-using System.Collections.Specialized;
-using System.IO;
-using System.Xml;
-using System.Reflection;
-using Mono.Addins.Description;
using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.IO;
using System.Linq;
-using Mono.Addins.Serialization;
+using System.Threading;
+using Mono.Addins.Description;
namespace Mono.Addins.Database
{
- class AddinDatabase
+ class AddinDatabase
{
public const string GlobalDomain = "global";
public const string UnknownDomain = "unknown";
public const string VersionTag = "004";
- List<Addin> allSetupInfos;
- List<Addin> addinSetupInfos;
- List<Addin> rootSetupInfos;
+ readonly AddinEngine addinEngine;
+ readonly AddinRegistry registry;
+ readonly string addinDbDir;
+ readonly FileDatabase fileDatabase;
+ readonly object localLock = new object ();
+
+ bool allSetupInfosLoaded;
+ ImmutableArray<Addin> allSetupInfos;
+ ImmutableArray<Addin> addinSetupInfos;
+ ImmutableArray<Addin> rootSetupInfos;
+
+ Dictionary<string, Addin> cachedAddinSetupInfos = new Dictionary<string, Addin> ();
+ ImmutableAddinHostIndex hostIndex;
+
internal static bool RunningSetupProcess;
+
bool fatalDatabseError;
- Hashtable cachedAddinSetupInfos = new Hashtable ();
- AddinHostIndex hostIndex;
- FileDatabase fileDatabase;
- string addinDbDir;
DatabaseConfiguration config = null;
- AddinRegistry registry;
int lastDomainId;
- AddinEngine addinEngine;
- AddinFileSystemExtension fs = new AddinFileSystemExtension ();
+ AddinFileSystemExtension fileSystemExtension = new AddinFileSystemExtension ();
List<object> extensions = new List<object> ();
public AddinDatabase (AddinEngine addinEngine, AddinRegistry registry)
@@ -71,13 +74,20 @@ namespace Mono.Addins.Database
addinDbDir = Path.Combine (registry.AddinCachePath, "addin-db-" + VersionTag);
fileDatabase = new FileDatabase (AddinDbDir);
}
-
+
+ public AddinDatabaseTransaction BeginTransaction (AddinEngineTransaction addinEngineTransaction = null)
+ {
+ return new AddinDatabaseTransaction (this, localLock, addinEngineTransaction);
+ }
+
+ internal AddinEngine AddinEngine => addinEngine;
+
string AddinDbDir {
get { return addinDbDir; }
}
public AddinFileSystemExtension FileSystem {
- get { return fs; }
+ get { return fileSystemExtension; }
}
public string AddinCachePath {
@@ -116,36 +126,34 @@ namespace Mono.Addins.Database
}
}
- public void Clear ()
- {
- if (Directory.Exists (AddinCachePath))
- Directory.Delete (AddinCachePath, true);
- if (Directory.Exists (AddinFolderCachePath))
- Directory.Delete (AddinFolderCachePath, true);
- }
-
public void CopyExtensions (AddinDatabase other)
{
- foreach (object o in other.extensions)
- RegisterExtension (o);
+ lock (extensions) {
+ foreach (object o in other.extensions)
+ RegisterExtension (o);
+ }
}
public void RegisterExtension (object extension)
{
- extensions.Add (extension);
- if (extension is AddinFileSystemExtension)
- fs = (AddinFileSystemExtension) extension;
- else
- throw new NotSupportedException ();
+ lock (extensions) {
+ extensions.Add (extension);
+ if (extension is AddinFileSystemExtension)
+ fileSystemExtension = (AddinFileSystemExtension)extension;
+ else
+ throw new NotSupportedException ();
+ }
}
public void UnregisterExtension (object extension)
{
- extensions.Remove (extension);
- if ((extension as AddinFileSystemExtension) == fs)
- fs = new AddinFileSystemExtension ();
- else
- throw new InvalidOperationException ();
+ lock (extensions) {
+ extensions.Remove (extension);
+ if ((extension as AddinFileSystemExtension) == fileSystemExtension)
+ fileSystemExtension = new AddinFileSystemExtension ();
+ else
+ throw new InvalidOperationException ();
+ }
}
public ExtensionNodeSet FindNodeSet (string domain, string addinId, string id)
@@ -190,98 +198,69 @@ namespace Mono.Addins.Database
// Get the cached list if the add-in list has already been loaded.
// The domain doesn't have to be checked again, since it is always the same
- IEnumerable<Addin> result = null;
-
- if ((flags & AddinSearchFlagsInternal.IncludeAll) == AddinSearchFlagsInternal.IncludeAll) {
- if (allSetupInfos != null)
- result = allSetupInfos;
- }
- else if ((flags & AddinSearchFlagsInternal.IncludeAddins) == AddinSearchFlagsInternal.IncludeAddins) {
- if (addinSetupInfos != null)
- result = addinSetupInfos;
- }
- else {
- if (rootSetupInfos != null)
- result = rootSetupInfos;
- }
-
- if (result == null) {
- InternalCheck (domain);
- using (fileDatabase.LockRead ()) {
- result = InternalGetInstalledAddins (domain, null, flags & ~AddinSearchFlagsInternal.LatestVersionsOnly);
- }
- }
-
- if ((flags & AddinSearchFlagsInternal.LatestVersionsOnly) == AddinSearchFlagsInternal.LatestVersionsOnly)
- result = result.Where (a => a.IsLatestVersion);
-
- if ((flags & AddinSearchFlagsInternal.ExcludePendingUninstall) == AddinSearchFlagsInternal.ExcludePendingUninstall)
- result = result.Where (a => !IsRegisteredForUninstall (a.Description.Domain, a.Id));
-
- return result;
+ return InternalGetInstalledAddins (domain, null, flags & ~AddinSearchFlagsInternal.LatestVersionsOnly, false);
}
- IEnumerable<Addin> InternalGetInstalledAddins (string domain, AddinSearchFlagsInternal type)
+ IEnumerable<Addin> InternalGetInstalledAddins (string domain, AddinSearchFlagsInternal type, bool dbIsLockedForRead)
{
- return InternalGetInstalledAddins (domain, null, type);
+ return InternalGetInstalledAddins (domain, null, type, dbIsLockedForRead);
}
- IEnumerable<Addin> InternalGetInstalledAddins (string domain, string idFilter, AddinSearchFlagsInternal type)
+ IEnumerable<Addin> InternalGetInstalledAddins (string domain, string idFilter, AddinSearchFlagsInternal type, bool dbIsLockedForRead)
{
- if ((type & AddinSearchFlagsInternal.LatestVersionsOnly) != 0)
- throw new InvalidOperationException ("LatestVersionsOnly flag not supported here");
-
- if (allSetupInfos == null) {
- Dictionary<string,Addin> adict = new Dictionary<string, Addin> ();
+ if (!allSetupInfosLoaded) {
+ lock (localLock) {
+ if (!allSetupInfosLoaded) {
+ Dictionary<string, Addin> adict = new Dictionary<string, Addin> ();
- // Global add-ins are valid for any private domain
- if (domain != AddinDatabase.GlobalDomain)
- FindInstalledAddins (adict, AddinDatabase.GlobalDomain, idFilter);
+ using (!dbIsLockedForRead ? fileDatabase.LockRead() : null) {
+ // Global add-ins are valid for any private domain
+ if (domain != AddinDatabase.GlobalDomain)
+ FindInstalledAddins (adict, AddinDatabase.GlobalDomain);
- FindInstalledAddins (adict, domain, idFilter);
- List<Addin> alist = new List<Addin> (adict.Values);
- UpdateLastVersionFlags (alist);
- if (idFilter != null)
- return alist;
- allSetupInfos = alist;
- }
- if ((type & AddinSearchFlagsInternal.IncludeAll) == AddinSearchFlagsInternal.IncludeAll)
- return FilterById (allSetupInfos, idFilter);
-
- if ((type & AddinSearchFlagsInternal.IncludeAddins) == AddinSearchFlagsInternal.IncludeAddins) {
- if (addinSetupInfos == null) {
- addinSetupInfos = new List<Addin> ();
- foreach (Addin adn in allSetupInfos)
- if (!adn.Description.IsRoot)
- addinSetupInfos.Add (adn);
+ FindInstalledAddins (adict, domain);
+ }
+ List<Addin> alist = new List<Addin> (adict.Values);
+ UpdateLastVersionFlags (alist);
+ allSetupInfos = alist.ToImmutableArray ();
+ addinSetupInfos = alist.Where (addin => !addin.Description.IsRoot).ToImmutableArray ();
+ rootSetupInfos = alist.Where (addin => addin.Description.IsRoot).ToImmutableArray ();
+ allSetupInfosLoaded = true;
+ }
}
- return FilterById (addinSetupInfos, idFilter);
}
- else {
- if (rootSetupInfos == null) {
- rootSetupInfos = new List<Addin> ();
- foreach (Addin adn in allSetupInfos)
- if (adn.Description.IsRoot)
- rootSetupInfos.Add (adn);
- }
- return FilterById (rootSetupInfos, idFilter);
+ IEnumerable<Addin> result;
+
+ if ((type & AddinSearchFlagsInternal.IncludeAll) == AddinSearchFlagsInternal.IncludeAll) {
+ result = allSetupInfos;
+ } else if ((type & AddinSearchFlagsInternal.IncludeAddins) == AddinSearchFlagsInternal.IncludeAddins) {
+ result = addinSetupInfos;
+ } else {
+ result = rootSetupInfos;
}
+
+ result = FilterById (result, idFilter);
+
+ if ((type & AddinSearchFlagsInternal.LatestVersionsOnly) == AddinSearchFlagsInternal.LatestVersionsOnly)
+ result = result.Where (a => a.IsLatestVersion);
+
+ if ((type & AddinSearchFlagsInternal.ExcludePendingUninstall) == AddinSearchFlagsInternal.ExcludePendingUninstall)
+ result = result.Where (a => !IsRegisteredForUninstall (a.Description.Domain, a.Id));
+ return result;
}
-
- IEnumerable<Addin> FilterById (List<Addin> addins, string id)
+
+ IEnumerable<Addin> FilterById (IEnumerable<Addin> addins, string id)
{
if (id == null)
return addins;
return addins.Where (a => Addin.GetIdName (a.Id) == id);
}
- void FindInstalledAddins (Dictionary<string,Addin> result, string domain, string idFilter)
+ void FindInstalledAddins (Dictionary<string,Addin> result, string domain)
{
- if (idFilter == null)
- idFilter = "*";
string dir = Path.Combine (AddinCachePath, domain);
if (Directory.Exists (dir)) {
- foreach (string file in fileDatabase.GetDirectoryFiles (dir, idFilter + ",*.maddin")) {
+ foreach (string file in fileDatabase.GetDirectoryFiles (dir, "*,*.maddin")) {
string id = Path.GetFileNameWithoutExtension (file);
if (!result.ContainsKey (id)) {
var adesc = GetInstalledDomainAddin (domain, id, true, false, false);
@@ -330,23 +309,26 @@ namespace Mono.Addins.Database
else
return null;
}
-
+
Addin GetInstalledDomainAddin (string domain, string id, bool exactVersionMatch, bool enabledOnly, bool dbLockCheck)
{
- Addin sinfo = null;
string idd = id + " " + domain;
- object ob = cachedAddinSetupInfos [idd];
- if (ob != null) {
- sinfo = ob as Addin;
+ Addin sinfo;
+ bool found;
+ lock (cachedAddinSetupInfos) {
+ found = cachedAddinSetupInfos.TryGetValue (idd, out sinfo);
+ }
+
+ if (found) {
if (sinfo != null) {
if (!enabledOnly || sinfo.Enabled)
return sinfo;
if (exactVersionMatch)
return null;
- }
- else if (enabledOnly)
+ } else if (enabledOnly) {
// Ignore the 'not installed' flag when disabled add-ins are allowed
return null;
+ }
}
if (dbLockCheck)
@@ -376,13 +358,15 @@ namespace Mono.Addins.Database
}
if (foundDomain != null) {
sinfo = new Addin (this, foundDomain, id);
- cachedAddinSetupInfos [idd] = sinfo;
- if (!enabledOnly || sinfo.Enabled)
- return sinfo;
- if (exactVersionMatch) {
- // Cache lookups with negative result
- cachedAddinSetupInfos [idd] = this;
- return null;
+ lock (cachedAddinSetupInfos) {
+ cachedAddinSetupInfos [idd] = sinfo;
+ if (!enabledOnly || sinfo.Enabled)
+ return sinfo;
+ if (exactVersionMatch) {
+ // Cache lookups with negative result
+ cachedAddinSetupInfos [idd] = null;
+ return null;
+ }
}
}
}
@@ -393,7 +377,7 @@ namespace Mono.Addins.Database
string bestVersion = null;
Addin.GetIdParts (id, out name, out version);
- foreach (Addin ia in InternalGetInstalledAddins (domain, name, AddinSearchFlagsInternal.IncludeAll))
+ foreach (Addin ia in InternalGetInstalledAddins (domain, name, AddinSearchFlagsInternal.IncludeAll, true))
{
if ((!enabledOnly || ia.Enabled) &&
(version.Length == 0 || ia.SupportsVersion (version)) &&
@@ -404,15 +388,20 @@ namespace Mono.Addins.Database
}
}
if (sinfo != null) {
- cachedAddinSetupInfos [idd] = sinfo;
+ lock (cachedAddinSetupInfos) {
+ cachedAddinSetupInfos [idd] = sinfo;
+ }
return sinfo;
}
}
-
+
// Cache lookups with negative result
// Ignore the 'not installed' flag when disabled add-ins are allowed
- if (enabledOnly)
- cachedAddinSetupInfos [idd] = this;
+ if (enabledOnly) {
+ lock (cachedAddinSetupInfos) {
+ cachedAddinSetupInfos [idd] = null;
+ }
+ }
return null;
}
}
@@ -426,20 +415,22 @@ namespace Mono.Addins.Database
{
InternalCheck (domain);
Addin ainfo = null;
-
- object ob = cachedAddinSetupInfos [assemblyLocation];
- if (ob != null)
- return ob as Addin; // Don't use a cast here is ob may not be an Addin.
- AddinHostIndex index = GetAddinHostIndex ();
+ lock (cachedAddinSetupInfos) {
+ if (cachedAddinSetupInfos.TryGetValue (assemblyLocation, out var ob))
+ return ob; // this can be null, if the add-in is disabled
+ }
+
+ var index = GetAddinHostIndex ();
string addin, addinFile, rdomain;
if (index.GetAddinForAssembly (assemblyLocation, out addin, out addinFile, out rdomain)) {
string sid = addin + " " + rdomain;
- ainfo = cachedAddinSetupInfos [sid] as Addin;
- if (ainfo == null)
- ainfo = new Addin (this, rdomain, addin);
- cachedAddinSetupInfos [assemblyLocation] = ainfo;
- cachedAddinSetupInfos [addin + " " + rdomain] = ainfo;
+ lock (cachedAddinSetupInfos) {
+ if (!cachedAddinSetupInfos.TryGetValue(sid, out ainfo))
+ ainfo = new Addin (this, rdomain, addin);
+ cachedAddinSetupInfos [assemblyLocation] = ainfo;
+ cachedAddinSetupInfos [sid] = ainfo;
+ }
}
return ainfo;
@@ -469,8 +460,14 @@ namespace Mono.Addins.Database
{
EnableAddin (domain, id, true);
}
-
- internal void EnableAddin (string domain, string id, bool exactVersionMatch)
+
+ public void EnableAddin (string domain, string id, bool exactVersionMatch)
+ {
+ using var transaction = BeginTransaction ();
+ EnableAddin (transaction, domain, id, exactVersionMatch);
+ }
+
+ void EnableAddin (AddinDatabaseTransaction dbTransaction, string domain, string id, bool exactVersionMatch)
{
Addin ainfo = GetInstalledAddin (domain, id, exactVersionMatch, false);
if (ainfo == null)
@@ -486,19 +483,26 @@ namespace Mono.Addins.Database
if (dep is AddinDependency) {
AddinDependency adep = dep as AddinDependency;
string adepid = Addin.GetFullId (ainfo.AddinInfo.Namespace, adep.AddinId, adep.Version);
- EnableAddin (domain, adepid, false);
+ EnableAddin (dbTransaction, domain, adepid, false);
}
}
- Configuration.SetEnabled (id, true, ainfo.AddinInfo.EnabledByDefault, true);
- SaveConfiguration ();
+ Configuration.SetEnabled (dbTransaction, id, true, ainfo.AddinInfo.EnabledByDefault, true);
+ SaveConfiguration (dbTransaction);
- if (addinEngine != null && addinEngine.IsInitialized)
- addinEngine.ActivateAddin (id);
+ if (addinEngine != null && addinEngine.IsInitialized) {
+ addinEngine.ActivateAddin (dbTransaction.GetAddinEngineTransaction(), id);
+ }
}
-
+
public void DisableAddin (string domain, string id, bool exactVersionMatch = false, bool onlyForCurrentSession = false)
{
+ using var transaction = BeginTransaction ();
+ DisableAddin (transaction, domain, id, exactVersionMatch, onlyForCurrentSession);
+ }
+
+ void DisableAddin (AddinDatabaseTransaction dbTransaction, string domain, string id, bool exactVersionMatch = false, bool onlyForCurrentSession = false)
+ {
Addin ai = GetInstalledAddin (domain, id, true);
if (ai == null)
throw new InvalidOperationException ("Add-in '" + id + "' not installed.");
@@ -506,8 +510,8 @@ namespace Mono.Addins.Database
if (!IsAddinEnabled (domain, id, exactVersionMatch))
return;
- Configuration.SetEnabled (id, false, ai.AddinInfo.EnabledByDefault, exactVersionMatch, onlyForCurrentSession);
- SaveConfiguration ();
+ Configuration.SetEnabled (dbTransaction, id, false, ai.AddinInfo.EnabledByDefault, exactVersionMatch, onlyForCurrentSession);
+ SaveConfiguration (dbTransaction);
// Disable all add-ins which depend on it
@@ -531,7 +535,7 @@ namespace Mono.Addins.Database
Addin adepinfo = GetInstalledAddin (domain, adepid, false, true);
if (adepinfo == null) {
- DisableAddin (domain, ainfo.Id, onlyForCurrentSession: onlyForCurrentSession);
+ DisableAddin (dbTransaction, domain, ainfo.Id, onlyForCurrentSession: onlyForCurrentSession);
break;
}
}
@@ -539,25 +543,26 @@ namespace Mono.Addins.Database
}
catch {
// If something goes wrong, enable the add-in again
- Configuration.SetEnabled (id, true, ai.AddinInfo.EnabledByDefault, false, onlyForCurrentSession);
- SaveConfiguration ();
+ Configuration.SetEnabled (dbTransaction, id, true, ai.AddinInfo.EnabledByDefault, false, onlyForCurrentSession);
+ SaveConfiguration (dbTransaction);
throw;
}
- if (addinEngine != null && addinEngine.IsInitialized)
- addinEngine.UnloadAddin (id);
+ if (addinEngine != null && addinEngine.IsInitialized) {
+ addinEngine.UnloadAddin (dbTransaction.GetAddinEngineTransaction(), id);
+ }
}
- public void UpdateEnabledStatus ()
+ void UpdateEnabledStatus (AddinDatabaseTransaction transaction)
{
// Ensure that all enabled addins that have dependencies also have their dependencies enabled.
HashSet<Addin> updatedAddins = new HashSet<Addin> ();
var allAddins = GetInstalledAddins (registry.CurrentDomain, AddinSearchFlagsInternal.IncludeAddins | AddinSearchFlagsInternal.LatestVersionsOnly).ToList ();
foreach (Addin addin in allAddins)
- UpdateEnabledStatus (registry.CurrentDomain, addin, allAddins, updatedAddins);
+ UpdateEnabledStatus (transaction, registry.CurrentDomain, addin, allAddins, updatedAddins);
}
- void UpdateEnabledStatus (string domain, Addin addin, List<Addin> allAddins, HashSet<Addin> updatedAddins)
+ void UpdateEnabledStatus (AddinDatabaseTransaction transaction, string domain, Addin addin, List<Addin> allAddins, HashSet<Addin> updatedAddins)
{
if (!updatedAddins.Add (addin))
return;
@@ -575,12 +580,12 @@ namespace Mono.Addins.Database
string adepid = Addin.GetFullId (addin.AddinInfo.Namespace, adep.AddinId, null);
var dependency = allAddins.FirstOrDefault (a => Addin.GetFullId (a.Namespace, a.LocalId, null) == adepid);
if (dependency != null) {
- UpdateEnabledStatus (domain, dependency, allAddins, updatedAddins);
+ UpdateEnabledStatus (transaction, domain, dependency, allAddins, updatedAddins);
if (!dependency.Enabled) {
// One of the dependencies is disabled, so this add-in also needs to be disabled.
// However, we disabled only for the current configuration, we don't want to change
// what the user configured.
- DisableAddin (domain, addin.Id, onlyForCurrentSession: true);
+ DisableAddin (transaction, domain, addin.Id, onlyForCurrentSession: true);
return;
}
}
@@ -589,9 +594,10 @@ namespace Mono.Addins.Database
public void RegisterForUninstall (string domain, string id, IEnumerable<string> files)
{
- DisableAddin (domain, id, true);
- Configuration.RegisterForUninstall (id, files);
- SaveConfiguration ();
+ using var transaction = BeginTransaction ();
+ DisableAddin (transaction, domain, id, true);
+ Configuration.RegisterForUninstall (transaction, id, files);
+ SaveConfiguration (transaction);
}
public bool IsRegisteredForUninstall (string domain, string addinId)
@@ -630,7 +636,8 @@ namespace Mono.Addins.Database
AddinUpdateData updateData = new AddinUpdateData (this, monitor);
// Clear cached data
- cachedAddinSetupInfos.Clear ();
+ lock(cachedAddinSetupInfos)
+ cachedAddinSetupInfos.Clear ();
// Collect all information
@@ -703,7 +710,7 @@ namespace Mono.Addins.Database
}
// If the original file does not exist, the description can be deleted
- if (!fs.FileExists (conf.AddinFile)) {
+ if (!fileSystemExtension.FileExists (conf.AddinFile)) {
SafeDelete (monitor, file);
continue;
}
@@ -1012,19 +1019,19 @@ namespace Mono.Addins.Database
internal void ResetBasicCachedData ()
{
- allSetupInfos = null;
- addinSetupInfos = null;
- rootSetupInfos = null;
+ lock(localLock)
+ allSetupInfosLoaded = false;
}
- internal void ResetCachedData ()
+ internal void ResetCachedData (AddinDatabaseTransaction dbTransaction = null)
{
ResetBasicCachedData ();
hostIndex = null;
- cachedAddinSetupInfos.Clear ();
+ lock(cachedAddinSetupInfos)
+ cachedAddinSetupInfos.Clear ();
dependsOnCache.Clear ();
if (addinEngine != null)
- addinEngine.ResetCachedData ();
+ addinEngine.ResetCachedData (dbTransaction?.GetAddinEngineTransaction());
}
Dictionary<string, HashSet<string>> dependsOnCache = new Dictionary<string, HashSet<string>> ();
@@ -1088,79 +1095,87 @@ namespace Mono.Addins.Database
Update (monitor, domain, context);
}
-
- public void Update (IProgressStatus monitor, string domain, ScanOptions context = null)
+
+ public void Update(IProgressStatus monitor, string domain, ScanOptions context = null, AddinEngineTransaction addinEngineTransaction = null)
{
if (monitor == null)
- monitor = new ConsoleProgressStatus (false);
+ monitor = new ConsoleProgressStatus(false);
if (RunningSetupProcess)
return;
-
+
fatalDatabseError = false;
-
+
DateTime tim = DateTime.Now;
-
- RunPendingUninstalls (monitor);
-
- Hashtable installed = new Hashtable ();
- bool changesFound = CheckFolders (monitor, domain);
-
+
+ using var dbTransaction = BeginTransaction(addinEngineTransaction);
+
+ RunPendingUninstalls(dbTransaction, monitor);
+
+ Hashtable installed = new Hashtable();
+ bool changesFound = CheckFolders(monitor, domain);
+
if (monitor.IsCanceled)
return;
-
+
if (monitor.LogLevel > 1)
- monitor.Log ("Folders checked (" + (int) (DateTime.Now - tim).TotalMilliseconds + " ms)");
-
- if (changesFound) {
+ monitor.Log("Folders checked (" + (int)(DateTime.Now - tim).TotalMilliseconds + " ms)");
+
+ if (changesFound)
+ {
// Something has changed, the add-ins need to be re-scanned, but it has
// to be done in an external process
-
- if (domain != null) {
- using (fileDatabase.LockRead ()) {
- foreach (Addin ainfo in InternalGetInstalledAddins (domain, AddinSearchFlagsInternal.IncludeAddins)) {
- installed [ainfo.Id] = ainfo.Id;
- }
+
+ if (domain != null)
+ {
+ foreach (Addin ainfo in InternalGetInstalledAddins(domain, AddinSearchFlagsInternal.IncludeAddins, false))
+ {
+ installed[ainfo.Id] = ainfo.Id;
}
}
-
- RunScannerProcess (monitor, context);
-
- ResetCachedData ();
-
- registry.NotifyDatabaseUpdated ();
+
+ RunScannerProcess(monitor, context);
+
+ ResetCachedData(dbTransaction);
+
+ registry.NotifyDatabaseUpdated();
}
-
+
if (fatalDatabseError)
- monitor.ReportError ("The add-in database could not be updated. It may be due to file corruption. Try running the setup repair utility", null);
-
+ monitor.ReportError("The add-in database could not be updated. It may be due to file corruption. Try running the setup repair utility", null);
+
// Update the currently loaded add-ins
- if (changesFound && domain != null && addinEngine != null && addinEngine.IsInitialized) {
- Hashtable newInstalled = new Hashtable ();
- foreach (Addin ainfo in GetInstalledAddins (domain, AddinSearchFlagsInternal.IncludeAddins)) {
- newInstalled [ainfo.Id] = ainfo.Id;
+ if (changesFound && domain != null && addinEngine != null && addinEngine.IsInitialized)
+ {
+ Hashtable newInstalled = new Hashtable();
+ foreach (Addin ainfo in GetInstalledAddins(domain, AddinSearchFlagsInternal.IncludeAddins))
+ {
+ newInstalled[ainfo.Id] = ainfo.Id;
}
-
- foreach (string aid in installed.Keys) {
+
+ foreach (string aid in installed.Keys)
+ {
// Always try to unload, event if the add-in was not currently loaded.
// Required since the add-ins has to be marked as 'disabled', to avoid
// extensions from this add-in to be loaded
- if (!newInstalled.Contains (aid))
- addinEngine.UnloadAddin (aid);
+ if (!newInstalled.Contains(aid))
+ addinEngine.UnloadAddin(dbTransaction.GetAddinEngineTransaction(), aid);
}
-
- foreach (string aid in newInstalled.Keys) {
- if (!installed.Contains (aid)) {
- Addin addin = addinEngine.Registry.GetAddin (aid);
+
+ foreach (string aid in newInstalled.Keys)
+ {
+ if (!installed.Contains(aid))
+ {
+ Addin addin = addinEngine.Registry.GetAddin(aid);
if (addin != null)
- addinEngine.ActivateAddin (aid);
+ addinEngine.ActivateAddin(dbTransaction.GetAddinEngineTransaction(), aid);
}
}
}
- UpdateEnabledStatus ();
+ UpdateEnabledStatus(dbTransaction);
}
- void RunPendingUninstalls (IProgressStatus monitor)
+ void RunPendingUninstalls (AddinDatabaseTransaction dbTransaction, IProgressStatus monitor)
{
bool changesDone = false;
@@ -1198,12 +1213,12 @@ namespace Mono.Addins.Database
}
if (canUninstall) {
- Configuration.UnregisterForUninstall (adn.AddinId);
+ Configuration.UnregisterForUninstall (dbTransaction, adn.AddinId);
changesDone = true;
}
}
if (changesDone)
- SaveConfiguration ();
+ SaveConfiguration (dbTransaction);
}
void RunScannerProcess (IProgressStatus monitor, ScanOptions context)
@@ -1214,8 +1229,8 @@ namespace Mono.Addins.Database
IProgressStatus scanMonitor = monitor;
context = context ?? new ScanOptions ();
- if (fs.GetType () != typeof (AddinFileSystemExtension))
- context.FileSystemExtension = fs;
+ if (fileSystemExtension.GetType () != typeof (AddinFileSystemExtension))
+ context.FileSystemExtension = fileSystemExtension;
bool retry = false;
do {
@@ -1350,10 +1365,10 @@ namespace Mono.Addins.Database
void InternalScanFolders (IProgressStatus monitor, AddinScanResult scanResult)
{
try {
- fs.ScanStarted ();
+ fileSystemExtension.ScanStarted ();
InternalScanFolders2 (monitor, scanResult);
} finally {
- fs.ScanFinished ();
+ fileSystemExtension.ScanFinished ();
}
}
@@ -1366,7 +1381,7 @@ namespace Mono.Addins.Database
return;
try {
- scanResult.HostIndex = GetAddinHostIndex ();
+ scanResult.HostIndex = new AddinHostIndex(GetAddinHostIndex ());
}
catch (Exception ex) {
if (scanResult.CheckOnly) {
@@ -1385,7 +1400,7 @@ namespace Mono.Addins.Database
AddinScanFolderInfo folderInfo;
bool res = ReadFolderInfo (monitor, file, out folderInfo);
bool validForDomain = scanResult.Domain == null || folderInfo.Domain == GlobalDomain || folderInfo.Domain == scanResult.Domain;
- if (!res || (validForDomain && !fs.DirectoryExists (folderInfo.Folder))) {
+ if (!res || (validForDomain && !fileSystemExtension.DirectoryExists (folderInfo.Folder))) {
if (res) {
// Folder has been deleted. Remove the add-ins it had.
updater.UpdateDeletedAddins (monitor, folderInfo);
@@ -1444,7 +1459,7 @@ namespace Mono.Addins.Database
if (monitor.LogLevel > 1)
monitor.Log ("Folders scan completed (" + (int) (DateTime.Now - tim).TotalMilliseconds + " ms)");
- SaveAddinHostIndex ();
+ SaveAddinHostIndex (scanResult);
ResetCachedData ();
if (!scanResult.ChangesFound) {
@@ -1472,7 +1487,9 @@ namespace Mono.Addins.Database
if (monitor.LogLevel > 1)
monitor.Log ("Add-in relations analyzed (" + (int) (DateTime.Now - tim).TotalMilliseconds + " ms)");
- SaveAddinHostIndex ();
+ SaveAddinHostIndex (scanResult);
+
+ hostIndex = scanResult.HostIndex.ToImmutableAddinHostIndex ();
}
public void ParseAddin (IProgressStatus progressStatus, string domain, string file, string outFile, bool inProcess)
@@ -1768,25 +1785,25 @@ namespace Mono.Addins.Database
return false;
}
}
-
- AddinHostIndex GetAddinHostIndex ()
+
+ ImmutableAddinHostIndex GetAddinHostIndex ()
{
if (hostIndex != null)
return hostIndex;
using (fileDatabase.LockRead ()) {
if (fileDatabase.Exists (HostIndexFile))
- hostIndex = AddinHostIndex.Read (fileDatabase, HostIndexFile);
+ hostIndex = AddinHostIndex.ReadAsImmutable (fileDatabase, HostIndexFile);
else
- hostIndex = new AddinHostIndex ();
+ hostIndex = new ImmutableAddinHostIndex ();
}
return hostIndex;
}
- void SaveAddinHostIndex ()
+ void SaveAddinHostIndex (AddinScanResult scanResult)
{
- if (hostIndex != null)
- hostIndex.Write (fileDatabase, HostIndexFile);
+ if (scanResult.HostIndex != null)
+ scanResult.HostIndex.Write (fileDatabase, HostIndexFile);
}
internal string GetUniqueAddinId (string file, string oldId, string ns, string version)
@@ -1844,18 +1861,20 @@ namespace Mono.Addins.Database
DatabaseConfiguration Configuration {
get {
if (config == null) {
- using (fileDatabase.LockRead ()) {
- if (fileDatabase.Exists (ConfigFile))
- config = DatabaseConfiguration.Read (ConfigFile);
- else
- config = DatabaseConfiguration.ReadAppConfig ();
+ lock (localLock) {
+ using (fileDatabase.LockRead ()) {
+ if (fileDatabase.Exists (ConfigFile))
+ config = DatabaseConfiguration.Read (ConfigFile);
+ else
+ config = DatabaseConfiguration.ReadAppConfig ();
+ }
}
}
return config;
}
}
- void SaveConfiguration ()
+ void SaveConfiguration (AddinDatabaseTransaction dbTransaction)
{
if (config != null) {
using (fileDatabase.LockWrite ()) {
@@ -1996,7 +2015,38 @@ namespace Mono.Addins.Database
list.Add (desc);
}
}
-
+
+ class AddinDatabaseTransaction : IDisposable
+ {
+ readonly AddinDatabase addinDatabase;
+ readonly object localLock;
+ AddinEngineTransaction addinEngineTransaction;
+ bool addinEngineTransactionStarted;
+
+ public AddinDatabaseTransaction (AddinDatabase addinDatabase, object localLock, AddinEngineTransaction addinEngineTransaction)
+ {
+ this.addinDatabase = addinDatabase;
+ this.localLock = localLock;
+ this.addinEngineTransaction = addinEngineTransaction;
+ Monitor.Enter (localLock);
+ }
+
+ public AddinEngineTransaction GetAddinEngineTransaction()
+ {
+ if (addinEngineTransaction != null)
+ return addinEngineTransaction;
+ addinEngineTransactionStarted = true;
+ return addinEngineTransaction = addinDatabase.AddinEngine.BeginEngineTransaction();
+ }
+
+ public void Dispose ()
+ {
+ Monitor.Exit(localLock);
+ if (addinEngineTransactionStarted)
+ addinEngineTransaction.Dispose();
+ }
+ }
+
// Keep in sync with AddinSearchFlags
[Flags]
enum AddinSearchFlagsInternal