Shorten shadow filesystems identifiers
This commit is contained in:
@@ -29,7 +29,7 @@ namespace Umbraco.Core.IO
|
||||
// shadow support
|
||||
private readonly List<ShadowWrapper> _shadowWrappers = new List<ShadowWrapper>();
|
||||
private readonly object _shadowLocker = new object();
|
||||
private static Guid _shadowCurrentId = Guid.Empty; // static - unique!!
|
||||
private static string _shadowCurrentId; // static - unique!!
|
||||
#region Constructor
|
||||
|
||||
// DI wants a public ctor
|
||||
@@ -45,13 +45,13 @@ namespace Umbraco.Core.IO
|
||||
_shadowWrappers.Clear();
|
||||
_filesystems.Clear();
|
||||
Volatile.Write(ref _wkfsInitialized, false);
|
||||
_shadowCurrentId = Guid.Empty;
|
||||
_shadowCurrentId = null;
|
||||
}
|
||||
|
||||
// for tests only, totally unsafe
|
||||
internal static void ResetShadowId()
|
||||
{
|
||||
_shadowCurrentId = Guid.Empty;
|
||||
_shadowCurrentId = null;
|
||||
}
|
||||
|
||||
// set by the scope provider when taking control of filesystems
|
||||
@@ -179,35 +179,37 @@ namespace Umbraco.Core.IO
|
||||
// global shadow for the entire application, so great care should be taken to ensure that the
|
||||
// application is *not* doing anything else when using a shadow.
|
||||
|
||||
internal ICompletable Shadow(Guid id)
|
||||
internal ICompletable Shadow()
|
||||
{
|
||||
if (Volatile.Read(ref _wkfsInitialized) == false) EnsureWellKnownFileSystems();
|
||||
|
||||
var id = ShadowWrapper.CreateShadowId();
|
||||
return new ShadowFileSystems(this, id); // will invoke BeginShadow and EndShadow
|
||||
}
|
||||
|
||||
internal void BeginShadow(Guid id)
|
||||
internal void BeginShadow(string id)
|
||||
{
|
||||
lock (_shadowLocker)
|
||||
{
|
||||
// if we throw here, it means that something very wrong happened.
|
||||
if (_shadowCurrentId != Guid.Empty)
|
||||
if (_shadowCurrentId != null)
|
||||
throw new InvalidOperationException("Already shadowing.");
|
||||
|
||||
_shadowCurrentId = id;
|
||||
|
||||
_logger.Debug<ShadowFileSystems>("Shadow '{ShadowId}'", id);
|
||||
_logger.Debug<ShadowFileSystems>("Shadow '{ShadowId}'", _shadowCurrentId);
|
||||
|
||||
foreach (var wrapper in _shadowWrappers)
|
||||
wrapper.Shadow(id);
|
||||
wrapper.Shadow(_shadowCurrentId);
|
||||
}
|
||||
}
|
||||
|
||||
internal void EndShadow(Guid id, bool completed)
|
||||
internal void EndShadow(string id, bool completed)
|
||||
{
|
||||
lock (_shadowLocker)
|
||||
{
|
||||
// if we throw here, it means that something very wrong happened.
|
||||
if (_shadowCurrentId == Guid.Empty)
|
||||
if (_shadowCurrentId == null)
|
||||
throw new InvalidOperationException("Not shadowing.");
|
||||
if (id != _shadowCurrentId)
|
||||
throw new InvalidOperationException("Not the current shadow.");
|
||||
@@ -228,7 +230,7 @@ namespace Umbraco.Core.IO
|
||||
}
|
||||
}
|
||||
|
||||
_shadowCurrentId = Guid.Empty;
|
||||
_shadowCurrentId = null;
|
||||
|
||||
if (exceptions.Count > 0)
|
||||
throw new AggregateException(completed ? "Failed to apply all changes (see exceptions)." : "Failed to abort (see exceptions).", exceptions);
|
||||
@@ -240,7 +242,7 @@ namespace Umbraco.Core.IO
|
||||
lock (_shadowLocker)
|
||||
{
|
||||
var wrapper = new ShadowWrapper(filesystem, shadowPath, IsScoped);
|
||||
if (_shadowCurrentId != Guid.Empty)
|
||||
if (_shadowCurrentId != null)
|
||||
wrapper.Shadow(_shadowCurrentId);
|
||||
_shadowWrappers.Add(wrapper);
|
||||
return wrapper;
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Umbraco.Core.IO
|
||||
private bool _completed;
|
||||
|
||||
// invoked by the filesystems when shadowing
|
||||
public ShadowFileSystems(FileSystems fileSystems, Guid id)
|
||||
public ShadowFileSystems(FileSystems fileSystems, string id)
|
||||
{
|
||||
_fileSystems = fileSystems;
|
||||
Id = id;
|
||||
@@ -19,7 +19,7 @@ namespace Umbraco.Core.IO
|
||||
}
|
||||
|
||||
// for tests
|
||||
public Guid Id { get; }
|
||||
public string Id { get; }
|
||||
|
||||
// invoked by the scope when exiting, if completed
|
||||
public void Complete()
|
||||
|
||||
@@ -22,7 +22,33 @@ namespace Umbraco.Core.IO
|
||||
_isScoped = isScoped;
|
||||
}
|
||||
|
||||
internal void Shadow(Guid id)
|
||||
public static string CreateShadowId()
|
||||
{
|
||||
const int retries = 50; // avoid infinite loop
|
||||
const int idLength = 6; // 6 chars
|
||||
|
||||
// shorten a Guid to idLength chars, and see whether it collides
|
||||
// with an existing directory or not - if it does, try again, and
|
||||
// we should end up with a unique identifier eventually - but just
|
||||
// detect infinite loops (just in case)
|
||||
|
||||
for (var i = 0; i < retries; i++)
|
||||
{
|
||||
var id = Guid.NewGuid().ToString("N").Substring(0, idLength);
|
||||
|
||||
var virt = ShadowFsPath + "/" + id;
|
||||
var shadowDir = IOHelper.MapPath(virt);
|
||||
if (Directory.Exists(shadowDir))
|
||||
continue;
|
||||
|
||||
Directory.CreateDirectory(shadowDir);
|
||||
return id;
|
||||
}
|
||||
|
||||
throw new Exception($"Could not get a shadow identifier (tried {retries} times)");
|
||||
}
|
||||
|
||||
internal void Shadow(string id)
|
||||
{
|
||||
// note: no thread-safety here, because ShadowFs is thread-safe due to the check
|
||||
// on ShadowFileSystemsScope.None - and if None is false then we should be running
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace Umbraco.Core.Scoping
|
||||
|
||||
// see note below
|
||||
if (scopeFileSystems == true)
|
||||
_fscope = fileSystems.Shadow(Guid.NewGuid());
|
||||
_fscope = fileSystems.Shadow();
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -105,7 +105,7 @@ namespace Umbraco.Core.Scoping
|
||||
// every scoped FS to trigger the creation of shadow FS "on demand", and that would be
|
||||
// pretty pointless since if scopeFileSystems is true, we *know* we want to shadow
|
||||
if (scopeFileSystems == true)
|
||||
_fscope = fileSystems.Shadow(Guid.NewGuid());
|
||||
_fscope = fileSystems.Shadow();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -405,10 +405,10 @@ namespace Umbraco.Tests.IO
|
||||
sw.AddFile("sub/f1.txt", ms);
|
||||
Assert.IsTrue(phy.FileExists("sub/f1.txt"));
|
||||
|
||||
Guid id;
|
||||
string id;
|
||||
|
||||
// explicit shadow without scope does not work
|
||||
sw.Shadow(id = Guid.NewGuid());
|
||||
sw.Shadow(id = ShadowWrapper.CreateShadowId());
|
||||
Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
sw.AddFile("sub/f2.txt", ms);
|
||||
@@ -419,7 +419,7 @@ namespace Umbraco.Tests.IO
|
||||
|
||||
// shadow with scope but no complete does not complete
|
||||
scopedFileSystems = true; // pretend we have a scope
|
||||
var scope = new ShadowFileSystems(fileSystems, id = Guid.NewGuid());
|
||||
var scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId());
|
||||
Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
sw.AddFile("sub/f3.txt", ms);
|
||||
@@ -440,7 +440,7 @@ namespace Umbraco.Tests.IO
|
||||
|
||||
// shadow with scope and complete does complete
|
||||
scopedFileSystems = true; // pretend we have a scope
|
||||
scope = new ShadowFileSystems(fileSystems, id = Guid.NewGuid());
|
||||
scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId());
|
||||
Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
sw.AddFile("sub/f4.txt", ms);
|
||||
@@ -456,7 +456,7 @@ namespace Umbraco.Tests.IO
|
||||
// test scope for "another thread"
|
||||
|
||||
scopedFileSystems = true; // pretend we have a scope
|
||||
scope = new ShadowFileSystems(fileSystems, id = Guid.NewGuid());
|
||||
scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId());
|
||||
Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
sw.AddFile("sub/f5.txt", ms);
|
||||
@@ -498,10 +498,10 @@ namespace Umbraco.Tests.IO
|
||||
sw.AddFile("sub/f1.txt", ms);
|
||||
Assert.IsTrue(phy.FileExists("sub/f1.txt"));
|
||||
|
||||
Guid id;
|
||||
string id;
|
||||
|
||||
scopedFileSystems = true; // pretend we have a scope
|
||||
var scope = new ShadowFileSystems(fileSystems, id = Guid.NewGuid());
|
||||
var scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId());
|
||||
Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
sw.AddFile("sub/f2.txt", ms);
|
||||
@@ -551,10 +551,10 @@ namespace Umbraco.Tests.IO
|
||||
sw.AddFile("sub/f1.txt", ms);
|
||||
Assert.IsTrue(phy.FileExists("sub/f1.txt"));
|
||||
|
||||
Guid id;
|
||||
string id;
|
||||
|
||||
scopedFileSystems = true; // pretend we have a scope
|
||||
var scope = new ShadowFileSystems(fileSystems, id = Guid.NewGuid());
|
||||
var scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId());
|
||||
Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
sw.AddFile("sub/f2.txt", ms);
|
||||
|
||||
Reference in New Issue
Block a user