// /** // * File: FSStorage.cs // * Author: haraldwolff // * // * This file and it's content is copyrighted by the Author and / or copyright holder. // * Any use wihtout proper permission is illegal and may lead to legal actions. // * // * // **/ using System; using System.Collections.Generic; using System.IO; using System.Diagnostics; using ln.logging; using ln.types.odb.ng.storage.cache; namespace ln.types.odb.ng.storage.fs { public class FSStorageContainer : IStorageContainer,IDisposable { public string BasePath { get; } public int DefaultCacheSize { get; set; } FileStream lockFile; Dictionary storages = new Dictionary(); public FSStorageContainer(string basePath) { BasePath = basePath; } public bool IsOpen => lockFile != null; private void AssertOpen() { if (!IsOpen) throw new IOException("FSStorage not open"); } public void Close() { lock (this) { AssertOpen(); foreach (IStorage storage in storages.Values) { if (storage.IsOpen) storage.Close(); storage.Dispose(); } if (lockFile != null) { lockFile.Close(); lockFile.Dispose(); lockFile = null; } } } public IStorage GetStorage(string storageName) { lock (this) { AssertOpen(); if (!storages.ContainsKey(storageName)) { IStorage storage = new SegmentedFileStorage(Path.Combine(BasePath, storageName)); if (DefaultCacheSize > 0) storage = new CachingStorage(storage) { MaxCacheSize = DefaultCacheSize, }; storages.Add(storageName, storage); } if (!storages[storageName].IsOpen) storages[storageName].Open(); return storages[storageName]; } } public IEnumerable GetStorageNames() { lock (this) { AssertOpen(); return storages.Keys; } } public IStorageContainer Open() { lock (this) { if (!IsOpen) { if (!Directory.Exists(BasePath)) Directory.CreateDirectory(BasePath); try { lockFile = new FileStream(Path.Combine(BasePath, ".lock"), FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read, 1024, FileOptions.DeleteOnClose); lockFile.WriteInteger(Process.GetCurrentProcess().Id); lockFile.Flush(); } catch (IOException) { if (File.Exists(Path.Combine(BasePath, ".lock"))) { lockFile = new FileStream(Path.Combine(BasePath, ".lock"), FileMode.Open, FileAccess.Read, FileShare.Read); int lockPID = lockFile.ReadInteger(); lockFile.Close(); Process lockProcess = null; try { lockProcess = Process.GetProcessById(lockPID); } catch (Exception) { } if ((lockProcess != null) && !lockProcess.HasExited) throw; Logging.Log(LogLevel.DEBUG, "FSStorageContainer: Ignoring stale lock file: PID:{0}@{1}", lockPID,Path.Combine(BasePath, ".lock")); lockFile = new FileStream(Path.Combine(BasePath, ".lock"), FileMode.Truncate, FileAccess.ReadWrite, FileShare.Read, 1024, FileOptions.DeleteOnClose); lockFile.WriteInteger(Process.GetCurrentProcess().Id); lockFile.Flush(); } } } } return this; } public void Dispose() { if (IsOpen) Close(); storages.Clear(); } } }