public static void BeforeEveryTest() { #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body try { Directory.Delete(TestAssetLocalStorageLmdbPartitionedLRUCtor.DATABASE_FOLDER_PATH, true); } catch { } #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body Directory.CreateDirectory(TestAssetLocalStorageLmdbPartitionedLRUCtor.DATABASE_FOLDER_PATH); var chattelConfigRead = new ChattelConfiguration(TestAssetLocalStorageLmdbPartitionedLRUCtor.DATABASE_FOLDER_PATH); var chattelConfigWrite = new ChattelConfiguration(TestAssetLocalStorageLmdbPartitionedLRUCtor.DATABASE_FOLDER_PATH); _readerLocalStorage = new AssetLocalStorageLmdbPartitionedLRU( chattelConfigRead, TestAssetLocalStorageLmdbPartitionedLRUCtor.DATABASE_MAX_SIZE_BYTES, TestAssetLocalStorageLmdbPartitionedLRUCtor.DATABASE_PARTITION_INTERVAL ); _chattelReader = new ChattelReader(chattelConfigRead, _readerLocalStorage); _chattelWriter = new ChattelWriter(chattelConfigWrite, _readerLocalStorage); _storageManager = new StorageManager( _readerLocalStorage, TimeSpan.FromMinutes(2), _chattelReader, _chattelWriter ); }
public static void TestChattelReader_GetAssetAsync2_UncachedAsset_SerialServer_ReturnsEqualAsset() { var server1 = Substitute.For <IAssetServer>(); var server2 = Substitute.For <IAssetServer>(); var config = new ChattelConfiguration(new List <List <IAssetServer> > { new List <IAssetServer> { server1 }, new List <IAssetServer> { server2 } }); var asset = new StratusAsset { Id = Guid.NewGuid(), Name = "Avengers", }; server1.WhenForAnyArgs(x => x.StoreAssetSync(asset)).Do(x => throw new AssetWriteException(asset.Id)); server2.RequestAssetSync(asset.Id).Returns(asset); var reader = new ChattelReader(config); var wait = new AutoResetEvent(false); reader.GetAssetAsync(asset.Id, resultAsset => { Assert.AreEqual(asset, resultAsset); wait.Set(); }); wait.WaitOne(); }
public static void TestChattelReader_GetAssetAsync2_CachedAsset_ReturnsEqualAsset() { var config = new ChattelConfiguration(LOCAL_STORAGE_DIR_INFO.FullName); var localStorage = Substitute.For <IChattelLocalStorage>(); var asset = new StratusAsset { Id = Guid.NewGuid(), Name = "Avengers", }; localStorage .TryGetAsset(asset.Id, out var junk) .Returns(x => { x[1] = asset; return(true); }) ; var reader = new ChattelReader(config, localStorage); var wait = new AutoResetEvent(false); reader.GetAssetAsync(asset.Id, resultAsset => { Assert.AreEqual(asset, resultAsset); wait.Set(); }); wait.WaitOne(); }
public static void TestStorageManager_GetAsset_DoubleNoExist_CallsServerRequestOnlyOnce() { LOG.Info($"Executing {nameof(TestStorageManager_GetAsset_DoubleNoExist_CallsServerRequestOnlyOnce)}"); // Tests the existence of a negative cache. var server = Substitute.For <IAssetServer>(); var config = new ChattelConfiguration(TestAssetLocalStorageLmdbPartitionedLRUCtor.DATABASE_FOLDER_PATH, WRITE_CACHE_FILE_PATH, WRITE_CACHE_MAX_RECORD_COUNT, server); using (var localStorage = new AssetLocalStorageLmdbPartitionedLRU( config, TestAssetLocalStorageLmdbPartitionedLRUCtor.DATABASE_MAX_SIZE_BYTES, TestAssetLocalStorageLmdbPartitionedLRUCtor.DATABASE_PARTITION_INTERVAL )) { var reader = new ChattelReader(config, localStorage, false); var writer = new ChattelWriter(config, localStorage, false); var assetId = Guid.NewGuid(); var mgr = new StorageManager( localStorage, TimeSpan.FromMinutes(2), reader, writer ); mgr.GetAsset(assetId, result => { }, () => { }); mgr.GetAsset(assetId, result => { }, () => { }); server.Received(1).RequestAssetSync(assetId); } }
[Timeout(900)] // Must be less than 2x the delay of the server. public static void TestChattelReader_GetAssetAsync2_UncachedAsset_SingleSlowServer_ParallelReads_SingleServerCall() { var server = Substitute.For <IAssetServer>(); var config = new ChattelConfiguration(server); var asset = new StratusAsset { Id = Guid.NewGuid(), Name = "Avengers", }; server .RequestAssetSync(asset.Id) .Returns(x => { Thread.Sleep(500); // Slow server call. return(asset); }) ; var reader = new ChattelReader(config); Parallel.Invoke( () => { reader.GetAssetAsync(asset.Id, resultAsset => { }); }, () => { reader.GetAssetAsync(asset.Id, resultAsset => { }); }, () => { reader.GetAssetAsync(asset.Id, resultAsset => { }); } ); // The server should only be hit once for multiple parallel calls for the same asset ID. server.Received(1).RequestAssetSync(asset.Id); }
public static void TestStorageManager_StoreAsset_CallsServerPutAsset() { LOG.Info($"Executing {nameof(TestStorageManager_StoreAsset_CallsServerPutAsset)}"); var server = Substitute.For <IAssetServer>(); var config = new ChattelConfiguration(TestAssetLocalStorageLmdbPartitionedLRUCtor.DATABASE_FOLDER_PATH, server); using (var readerLocalStorage = new AssetLocalStorageLmdbPartitionedLRU( config, uint.MaxValue, TestAssetLocalStorageLmdbPartitionedLRUCtor.DATABASE_PARTITION_INTERVAL )) { var reader = new ChattelReader(config, readerLocalStorage); var writer = new ChattelWriter(config, readerLocalStorage); var mgr = new StorageManager( readerLocalStorage, TimeSpan.FromMinutes(2), reader, writer ); var asset = new StratusAsset { Id = Guid.NewGuid(), }; var wait = new AutoResetEvent(false); mgr.StoreAsset(asset, result => wait.Set()); wait.WaitOne(); server.Received(1).StoreAssetSync(asset); } }
public static void TestChattelReader_HasUpstream_None_False() { var config = new ChattelConfiguration(LOCAL_STORAGE_DIR_INFO.FullName); var reader = new ChattelReader(config); Assert.False(reader.HasUpstream); }
public static void TestChattelReader_HasUpstream_Mocked_True() { var server = Substitute.For <IAssetServer>(); var config = new ChattelConfiguration(server); var reader = new ChattelReader(config); Assert.True(reader.HasUpstream); }
public void Init() { // Configure Log4Net XmlConfigurator.Configure(new FileInfo(Constants.LOG_CONFIG_PATH)); // Set CWD so that native libs are found. Directory.SetCurrentDirectory(TestContext.CurrentContext.TestDirectory); // Load INI stuff var configSource = new ArgvConfigSource(new string[] { }); // Configure nIni aliases and locale Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US", true); configSource.Alias.AddAlias("On", true); configSource.Alias.AddAlias("Off", false); configSource.Alias.AddAlias("True", true); configSource.Alias.AddAlias("False", false); configSource.Alias.AddAlias("Yes", true); configSource.Alias.AddAlias("No", false); // Read in the ini file configSource.Merge(new IniConfigSource(Constants.INI_PATH)); // Prep cache folder try { Directory.Delete(Constants.TEST_CACHE_PATH, true); } catch (DirectoryNotFoundException) { // Skip. } Directory.CreateDirectory(Constants.TEST_CACHE_PATH); // Start booting server var pidFileManager = new PIDFileManager(Constants.PID_FILE_PATH); var chattelConfigRead = new ChattelConfiguration(Constants.TEST_CACHE_PATH); LocalStorage = new AssetStorageSimpleFolderTree(chattelConfigRead); var chattelReader = new ChattelReader(chattelConfigRead, LocalStorage); _service = new F_Stop( Constants.SERVICE_URI, Constants.SERVICE_ADMIN_TOKEN, TimeSpan.FromSeconds(Constants.SERVICE_NC_LIFETIME_SECONDS), chattelReader, new List <sbyte> { 0, 12, /*18, 19,*/ 49 } ); _service.Start(); }
public static void CleanupAfterEveryTest() { LOG.Info($"Executing {nameof(CleanupAfterEveryTest)}"); _chattelReader = null; _chattelWriter = null; IDisposable localStorageDisposal = _readerLocalStorage; _readerLocalStorage = null; localStorageDisposal.Dispose(); TestAssetLocalStorageLmdbPartitionedLRUCtor.CleanLocalStorageFolder(TestAssetLocalStorageLmdbPartitionedLRUCtor.DATABASE_FOLDER_PATH, WRITE_CACHE_FILE_PATH); }
public static void BeforeEveryTest() { LOG.Info($"Executing {nameof(BeforeEveryTest)}"); TestAssetLocalStorageLmdbPartitionedLRUCtor.RebuildLocalStorageFolder(TestAssetLocalStorageLmdbPartitionedLRUCtor.DATABASE_FOLDER_PATH, WRITE_CACHE_FILE_PATH); _readerLocalStorage = new AssetLocalStorageLmdbPartitionedLRU( _chattelConfigRead, TestAssetLocalStorageLmdbPartitionedLRUCtor.DATABASE_MAX_SIZE_BYTES, TestAssetLocalStorageLmdbPartitionedLRUCtor.DATABASE_PARTITION_INTERVAL ); _chattelReader = new ChattelReader(_chattelConfigRead, _readerLocalStorage); _chattelWriter = new ChattelWriter(_chattelConfigWrite, _readerLocalStorage); }
public static void Initialize(ChattelReader assetReader) { if (_assetReader == null) { _assetReader = assetReader; } else { LOG.Warn($"Attempt to inialize the asset reader in the Texture class more than once! Re-initialization ignored."); } CSJ2K.Util.BitmapImageCreator.Register(); }
public static void TestChattelReader_GetAssetAsync3_NoUpstream_CacheRuleSkipReadWrite_LocalCacheIsNotWritten() { var config = new ChattelConfiguration(LOCAL_STORAGE_DIR_INFO.FullName); var localStorage = Substitute.For <IChattelLocalStorage>(); var asset = new StratusAsset { Id = Guid.NewGuid(), }; var reader = new ChattelReader(config, localStorage); reader.GetAssetAsync(asset.Id, resultAsset => {}, ChattelReader.CacheRule.SkipRead | ChattelReader.CacheRule.SkipWrite); localStorage.Received(0).StoreAsset(asset); }
public static void TestChattelReader_GetAssetAsync2_EmptyGuid_ReturnsNull() { var config = new ChattelConfiguration(LOCAL_STORAGE_DIR_INFO.FullName); var reader = new ChattelReader(config); var wait = new AutoResetEvent(false); reader.GetAssetAsync(Guid.Empty, resultAsset => { Assert.Null(resultAsset); wait.Set(); }); wait.WaitOne(); }
[Timeout(900)] // Must be less than 2x the delay of the server. public static void TestChattelReader_GetAssetAsync2_UncachedAsset_SingleSlowServer_ParallelReads_TakeExpectedTime() { var server = Substitute.For <IAssetServer>(); var config = new ChattelConfiguration(server); var asset = new StratusAsset { Id = Guid.NewGuid(), Name = "Avengers", }; server .RequestAssetSync(asset.Id) .Returns(x => { Thread.Sleep(500); // Slow server call. return(asset); }) ; var reader = new ChattelReader(config); var time1ms = 0L; var time2ms = 0L; Parallel.Invoke( () => { var timer = new Stopwatch(); timer.Restart(); reader.GetAssetAsync(asset.Id, resultAsset => { timer.Stop(); time1ms = timer.ElapsedMilliseconds; }); }, () => { var timer = new Stopwatch(); timer.Restart(); reader.GetAssetAsync(asset.Id, resultAsset => { timer.Stop(); time2ms = timer.ElapsedMilliseconds; }); } ); // Both calls are to take about the same time, as the server is going to take its jolly time getting back to us. Assert.Less(time1ms, 600); Assert.Greater(time1ms, 490); Assert.Less(time2ms, 600); Assert.Greater(time2ms, 490); }
public static void TestChattelReader_GetAssetAsync3_WithUpstream_CacheRuleSkipRead_LocalCacheIsWritten() { var server = Substitute.For <IAssetServer>(); var config = new ChattelConfiguration(LOCAL_STORAGE_DIR_INFO.FullName, server); var localStorage = Substitute.For <IChattelLocalStorage>(); var asset = new StratusAsset { Id = Guid.NewGuid(), }; server.RequestAssetSync(asset.Id).Returns(asset); var reader = new ChattelReader(config, localStorage); reader.GetAssetAsync(asset.Id, resultAsset => {}, ChattelReader.CacheRule.SkipRead); localStorage.Received(1).StoreAsset(asset); }
public static void TestChattelReader_GetAssetAsync2_EmptyGuid_CallbackCalled() { var config = new ChattelConfiguration(LOCAL_STORAGE_DIR_INFO.FullName); var reader = new ChattelReader(config); var wait = new AutoResetEvent(false); var callbackWasCalled = false; reader.GetAssetAsync(Guid.Empty, resultAsset => { callbackWasCalled = true; wait.Set(); }); wait.WaitOne(); Assert.True(callbackWasCalled); }
public TestLocalRead(uint assetDataSize) { _dataSize = assetDataSize; ChattelCleanup.CleanLocalStorageFolder(LOCAL_STORAGE_DIR_INFO); ChattelCleanup.CreateLocalStorageFolder(LOCAL_STORAGE_DIR_INFO); var config = new ChattelConfiguration(LOCAL_STORAGE_DIR_INFO.FullName); _reader = new ChattelReader(config); ChattelCleanup.CreateLocalStorageEntry(LOCAL_STORAGE_DIR_INFO, new InWorldz.Data.Assets.Stratus.StratusAsset { Id = _knownAssetId = Guid.NewGuid(), Name = "Adama", Data = new byte[_dataSize], }); }
public static void TestChattelReader_GetAssetAsync2_LocalCacheIsWritten() { // Simply need to verify that CacheRule.Normal is in effect. var server = Substitute.For <IAssetServer>(); var config = new ChattelConfiguration(LOCAL_STORAGE_DIR_INFO.FullName, server); var localStorage = Substitute.For <IChattelLocalStorage>(); var asset = new StratusAsset { Id = Guid.NewGuid(), }; server.RequestAssetSync(asset.Id).Returns(asset); var reader = new ChattelReader(config, localStorage); reader.GetAssetAsync(asset.Id, resultAsset => {}); localStorage.Received(1).StoreAsset(asset); }
public static void TestChattelReader_GetAssetAsync3_NoUpstream_CacheRuleSkipReadWrite_LocalCacheIsReadAnyway() { var config = new ChattelConfiguration(LOCAL_STORAGE_DIR_INFO.FullName); var localStorage = Substitute.For <IChattelLocalStorage>(); var assetId = Guid.NewGuid(); localStorage .TryGetAsset(assetId, out var junk) .Returns(x => { x[1] = new StratusAsset(); return(true); }) ; var reader = new ChattelReader(config, localStorage); reader.GetAssetAsync(assetId, resultAsset => {}, ChattelReader.CacheRule.SkipRead | ChattelReader.CacheRule.SkipWrite); localStorage.Received(1).TryGetAsset(assetId, out junk); }
/// <summary> /// Initializes a new instance of the <see cref="T:LibWhipLru.Cache.StorageManager"/> class. /// A zero or negative value for the negativeCacheItemLifetime results in the negative cache being disabled. /// </summary> /// <param name="localStorage">Local storage for assets.</param> /// <param name="negativeCacheItemLifetime">Negative cache item lifetime.</param> /// <param name="reader">Reader.</param> /// <param name="writer">Writer.</param> public StorageManager( AssetLocalStorageLmdbPartitionedLRU localStorage, TimeSpan negativeCacheItemLifetime, ChattelReader reader, ChattelWriter writer ) { _localStorage = localStorage ?? throw new ArgumentNullException(nameof(localStorage)); _assetReader = reader ?? throw new ArgumentNullException(nameof(reader)); _assetWriter = writer ?? throw new ArgumentNullException(nameof(writer)); if (negativeCacheItemLifetime.TotalSeconds > 0) { _negativeCache = System.Runtime.Caching.MemoryCache.Default; _negativeCacheLock = new ReaderWriterLockSlim(); _negativeCachePolicy = new System.Runtime.Caching.CacheItemPolicy { SlidingExpiration = negativeCacheItemLifetime, }; } }
public static void TestChattelReader_GetAssetAsync2_UncachedAsset_SingleServer_ReturnsEqualAsset() { var server = Substitute.For <IAssetServer>(); var config = new ChattelConfiguration(server); var asset = new StratusAsset { Id = Guid.NewGuid(), Name = "Avengers", }; server.RequestAssetSync(asset.Id).Returns(asset); var reader = new ChattelReader(config); var wait = new AutoResetEvent(false); reader.GetAssetAsync(asset.Id, resultAsset => { Assert.AreEqual(asset, resultAsset); wait.Set(); }); wait.WaitOne(); }
public static void TestChattelReader_GetAssetAsync2_LocalCacheIsRead() { // Simply need to verify that CacheRule.Normal is in effect. var config = new ChattelConfiguration(LOCAL_STORAGE_DIR_INFO.FullName); var localStorage = Substitute.For <IChattelLocalStorage>(); var assetId = Guid.NewGuid(); localStorage .TryGetAsset(assetId, out var junk) .Returns(x => { x[1] = new StratusAsset(); return(true); }) ; var reader = new ChattelReader(config, localStorage); reader.GetAssetAsync(assetId, resultAsset => {}); localStorage.Received(1).TryGetAsset(assetId, out junk); }
[Timeout(900)] // Must be less than 2x the delay of the server. public static void TestChattelReader_GetAssetAsync2_UncachedAsset_SingleSlowServer_ParallelReads_ReturnsEqualAssetToBoth() { var server = Substitute.For <IAssetServer>(); var config = new ChattelConfiguration(server); var asset = new StratusAsset { Id = Guid.NewGuid(), Name = "Avengers", }; server .RequestAssetSync(asset.Id) .Returns(x => { Thread.Sleep(500); // Slow server call. return(asset); }) ; var reader = new ChattelReader(config); StratusAsset asset1 = null; StratusAsset asset2 = null; Parallel.Invoke( () => { reader.GetAssetAsync(asset.Id, resultAsset => { asset1 = resultAsset; }); }, () => { reader.GetAssetAsync(asset.Id, resultAsset => { asset2 = resultAsset; }); } ); Assert.AreEqual(asset, asset1); Assert.AreEqual(asset, asset2); }
public TestMockRead(uint assetDataSize) { _dataSize = assetDataSize; ChattelCleanup.CreateLocalStorageFolder(LOCAL_STORAGE_DIR_INFO); var localStorage = Substitute.For <IChattelLocalStorage>(); var config = new ChattelConfiguration(LOCAL_STORAGE_DIR_INFO.FullName); _reader = new ChattelReader(config, localStorage); _knownAssetId = Guid.NewGuid(); localStorage .TryGetAsset(_knownAssetId, out var junk) .Returns(x => { x[1] = new InWorldz.Data.Assets.Stratus.StratusAsset { Id = _knownAssetId, Name = "Adama", Data = new byte[_dataSize], }; return(true); }) ; }
public static int Main(string[] args) { // First line, hook the appdomain to the crash reporter #pragma warning disable RECS0164 // Explicit delegate creation expression is redundant // Analysis disable once RedundantDelegateCreation // The "new" is required. AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); #pragma warning restore RECS0164 // Explicit delegate creation expression is redundant var watch = System.Diagnostics.Stopwatch.StartNew(); // Add the arguments supplied when running the application to the configuration var configSource = new ArgvConfigSource(args); _configSource = configSource; // Commandline switches configSource.AddSwitch("Startup", "inifile"); configSource.AddSwitch("Startup", "logconfig"); configSource.AddSwitch("Startup", "MaxParallelism", "p"); configSource.AddSwitch("Startup", "ServerMode"); var startupConfig = _configSource.Configs["Startup"]; // TODO: var pidFileManager = new PIDFileManager(startupConfig.GetString("pidfile", string.Empty)); // Configure Log4Net { var logConfigFile = startupConfig.GetString("logconfig", string.Empty); if (string.IsNullOrEmpty(logConfigFile)) { XmlConfigurator.Configure(); LogBootMessage(); LOG.Info("Configured log4net using ./Anaximander.exe.config as the default."); } else { XmlConfigurator.Configure(new FileInfo(logConfigFile)); LogBootMessage(); LOG.Info($"Configured log4net using \"{logConfigFile}\" as configuration file."); } } // Configure nIni aliases and localles Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US", true); configSource.Alias.AddAlias("On", true); configSource.Alias.AddAlias("Off", false); configSource.Alias.AddAlias("True", true); configSource.Alias.AddAlias("False", false); configSource.Alias.AddAlias("Yes", true); configSource.Alias.AddAlias("No", false); // Read in the ini file ReadConfigurationFromINI(configSource); var configRead = configSource.Configs["AssetsRead"]; var serversRead = GetServers(configSource, configRead, _assetServersByName); var chattelConfigRead = GetConfig(configRead, serversRead); // Create an IPC wait handle with a unique identifier. var serverMode = startupConfig.GetBoolean("ServerMode", Constants.KeepRunningDefault); var createdNew = true; var waitHandle = serverMode ? new EventWaitHandle(false, EventResetMode.AutoReset, "4d1ede7a-7f81-4934-bc59-f4fe10396408", out createdNew) : null; var serverState = serverMode ? ServerState.Starting : ServerState.Ignored; // If the handle was already there, inform the user and die. if (serverState == ServerState.Starting && !createdNew) { LOG.Error("Server process alredy started, please stop that server first."); return(2); } LOG.Info($"Configured for max degree of parallelism of {startupConfig.GetInt("MaxParallelism", Constants.MaxDegreeParallism)}"); var readerLocalStorage = new AssetStorageSimpleFolderTree(chattelConfigRead); var chattelReader = new ChattelReader(chattelConfigRead, readerLocalStorage); // TODO: add purge flag to CLI Texture.Initialize(chattelReader); watch.Stop(); LOG.Info($"Read configuration in {watch.ElapsedMilliseconds} ms."); watch.Restart(); // Load the RDB map try { _rdbMap = new RDBMap(configSource); } catch (DatabaseException e) { LOG.Error($"Unable to continue without database connection. Aborting.", e); return(1); } watch.Stop(); LOG.Info($"Loaded region DB in {watch.ElapsedMilliseconds} ms for a total of {_rdbMap.GetRegionCount()} regions, resulting in an average of {(float)watch.ElapsedMilliseconds / _rdbMap.GetRegionCount()} ms / region."); watch.Restart(); /* Issues to watch for: * Region delete - The DBA will need to actually remove the estate record to cause a map tile delete. * TODO: Tile image read during write - The web server could attempt to read a file while the file is being written. * - Possible solution: write to a random filename then try { mv rndname to finalname with overwrite } catch { try again later for a max of N times } * This should provide as much atomicity as possible, and allow anything that's blocking access to be bypassed via time delay. Needs to just fail under exceptions that indicate always-fail conditions. */ { LOG.Debug("Initializing writer and generator."); _tileWriter = new TileImageWriter(configSource); _tileGenerator = new TileGenerator(configSource); LOG.Debug("Writing ocean tile."); // Generate & replace ocean tile using (var ocean_tile = _tileGenerator.GenerateOceanTile()) { _tileWriter.WriteOceanTile(ocean_tile.Bitmap); } LOG.Debug("Generating a full batch of region tiles."); // Generate region tiles - all existing are nearly guaranteed to be out of date. var options = new ParallelOptions { MaxDegreeOfParallelism = startupConfig.GetInt("MaxParallelism", Constants.MaxDegreeParallism) }; // -1 means full parallel. 1 means non-parallel. Parallel.ForEach(_rdbMap.GetRegionUUIDs(), options, (region_id) => { var oldPriority = Thread.CurrentThread.Priority; try { Thread.CurrentThread.Priority = ThreadPriority.BelowNormal; UpdateRegionTile(region_id); } finally { Thread.CurrentThread.Priority = oldPriority; } }); watch.Stop(); LOG.Info($"Created full res map tiles in {watch.ElapsedMilliseconds} ms all regions with known locations, resulting in an average of {(float)watch.ElapsedMilliseconds / _rdbMap.GetRegionCount()} ms / region."); watch.Restart(); // Generate zoom level tiles. // Just quickly build the tile tree so that lookups of the super tiles can be done. var superGen = new SuperTileGenerator(configSource, _rdbMap); superGen.PreloadTileTrees(_rdbMap.GetRegionUUIDs()); watch.Stop(); LOG.Info($"Preloaded tile tree in {watch.ElapsedMilliseconds} ms."); watch.Restart(); // Remove all tiles that do not have a corresponding entry in the map. _tileWriter.RemoveDeadTiles(_rdbMap, superGen.AllNodesById); watch.Stop(); LOG.Info($"Removed all old tiles in {watch.ElapsedMilliseconds} ms."); watch.Restart(); // Actually generate the zoom level tiles. superGen.GeneratePreloadedTree(); watch.Stop(); LOG.Info($"Created all super tiles in {watch.ElapsedMilliseconds} ms."); } // Activate server process if (serverState == ServerState.Starting) { System.Console.CancelKeyPress += (sender, cargs) => { cargs.Cancel = true; waitHandle.Set(); }; serverState = ServerState.Running; var server_config = configSource.Configs["Server"]; var domain = server_config?.GetString("UseSSL", Constants.ServerDomain) ?? Constants.ServerDomain; var port = (uint)(server_config?.GetInt("UseSSL", Constants.ServerPort) ?? Constants.ServerPort); var useSSL = server_config?.GetBoolean("UseSSL", Constants.ServerUseSSL) ?? Constants.ServerUseSSL; var protocol = useSSL ? "https" : "http"; LOG.Info($"Activating server on '{protocol}://{domain}:{port}', listening for region updates."); RestApi.RestAPI.StartHost( UpdateRegionDelegate, MapRulesDelegate, CheckAPIKeyDelegate, domain, port, useSSL ); waitHandle.WaitOne(); serverState = ServerState.Stopping; } // I don't care what's still connected or keeping things running, it's time to die! Environment.Exit(0); return(0); }
public static int Main(string[] args) { // First line, hook the appdomain to the crash reporter AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; var createdNew = true; var waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset, "70a9f94f-59e8-4073-93ab-00aaacc26111", out createdNew); if (!createdNew) { LOG.Error("Server process already started, please stop that server first."); return(2); } // Add the arguments supplied when running the application to the configuration var configSource = new ArgvConfigSource(args); // Commandline switches configSource.AddSwitch("Startup", "inifile"); configSource.AddSwitch("Startup", "logconfig"); configSource.AddSwitch("Startup", "pidfile"); var startupConfig = configSource.Configs["Startup"]; var pidFileManager = new PIDFileManager(startupConfig.GetString("pidfile", string.Empty)); // Configure Log4Net var logConfigFile = startupConfig.GetString("logconfig", string.Empty); if (string.IsNullOrEmpty(logConfigFile)) { XmlConfigurator.Configure(); LogBootMessage(); LOG.Info("Configured log4net using ./WHIP_LRU.exe.config as the default."); } else { XmlConfigurator.Configure(new FileInfo(logConfigFile)); LogBootMessage(); LOG.Info($"Configured log4net using \"{logConfigFile}\" as configuration file."); } // Configure nIni aliases and locale Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US", true); configSource.Alias.AddAlias("On", true); configSource.Alias.AddAlias("Off", false); configSource.Alias.AddAlias("True", true); configSource.Alias.AddAlias("False", false); configSource.Alias.AddAlias("Yes", true); configSource.Alias.AddAlias("No", false); var isRunning = true; F_Stop f_stop = null; // Handlers for signals. Console.CancelKeyPress += (sender, cargs) => { LOG.Debug("CTRL-C pressed, terminating."); isRunning = false; f_stop?.Stop(); cargs.Cancel = true; waitHandle.Set(); }; // TODO: incorporate UNIX signals for reloading etc, once the crossplatform kinks have been worked out in WHIP-LRU. while (isRunning) { // Read in the ini file ReadConfigurationFromINI(configSource); var configRead = configSource.Configs["AssetsRead"]; var serversRead = GetServers(configSource, configRead, _assetServersByName); var chattelConfigRead = GetConfig(configRead, serversRead); var chattelReader = new ChattelReader(chattelConfigRead); var serverConfig = configSource.Configs["Server"]; var address = serverConfig?.GetString("Address", F_Stop.DEFAULT_ADDRESS) ?? F_Stop.DEFAULT_ADDRESS; if (address == "*") { address = "localhost"; } var port = (uint?)serverConfig?.GetInt("Port", (int)F_Stop.DEFAULT_PORT) ?? F_Stop.DEFAULT_PORT; var useSSL = serverConfig?.GetBoolean("UseSSL", F_Stop.DEFAULT_USE_SSL) ?? F_Stop.DEFAULT_USE_SSL; var adminToken = serverConfig?.GetString("AdminToken", F_Stop.DEFAULT_ADMIN_TOKEN) ?? F_Stop.DEFAULT_ADMIN_TOKEN; var validAssetTypes = serverConfig?.GetString("AllowedAssetTypes", F_Stop.DEFAULT_VALID_ASSET_TYPES) ?? F_Stop.DEFAULT_VALID_ASSET_TYPES; var cacheConfig = configSource.Configs["Cache"]; var negativeCacheItemLifetime = TimeSpan.FromSeconds((uint?)cacheConfig?.GetInt("NegativeCacheItemLifetimeSeconds", (int)F_Stop.DEFAULT_NC_LIFETIME_SECONDS) ?? F_Stop.DEFAULT_NC_LIFETIME_SECONDS); var protocol = useSSL ? "https" : "http"; var uri = new Uri($"{protocol}://{address}:{port}"); f_stop = new F_Stop( uri, adminToken, negativeCacheItemLifetime, chattelReader, validAssetTypes.Split(',').Select(type => sbyte.Parse(type)) ); f_stop.Start(); waitHandle.WaitOne(); } return(0); }
public void Init() { // Configure Log4Net XmlConfigurator.Configure(new FileInfo(Constants.LOG_CONFIG_PATH)); // Set CWD so that native libs are found. Directory.SetCurrentDirectory(TestContext.CurrentContext.TestDirectory); // Load INI stuff var configSource = new ArgvConfigSource(new string[] { }); // Configure nIni aliases and locale Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US", true); configSource.Alias.AddAlias("On", true); configSource.Alias.AddAlias("Off", false); configSource.Alias.AddAlias("True", true); configSource.Alias.AddAlias("False", false); configSource.Alias.AddAlias("Yes", true); configSource.Alias.AddAlias("No", false); // Read in the ini file configSource.Merge(new IniConfigSource(Constants.INI_PATH)); #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body try { Directory.Delete(DATABASE_FOLDER_PATH, true); } catch (Exception) { } try { File.Delete(WRITE_CACHE_FILE_PATH); } catch (Exception) { } #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body Directory.CreateDirectory(DATABASE_FOLDER_PATH); // Start booting server var pidFileManager = new LibWhipLru.Util.PIDFileManager(Constants.PID_FILE_PATH); var chattelConfigRead = new ChattelConfiguration(DATABASE_FOLDER_PATH); var chattelConfigWrite = new ChattelConfiguration(DATABASE_FOLDER_PATH); var readerLocalStorage = new LibWhipLru.Cache.AssetLocalStorageLmdbPartitionedLRU( chattelConfigRead, DATABASE_MAX_SIZE_BYTES, TimeSpan.FromSeconds(1) ); var chattelReader = new ChattelReader(chattelConfigRead, readerLocalStorage); var chattelWriter = new ChattelWriter(chattelConfigWrite, readerLocalStorage); var storageManager = new LibWhipLru.Cache.StorageManager( readerLocalStorage, TimeSpan.FromMinutes(2), chattelReader, chattelWriter ); _service = new WhipLru( Constants.SERVICE_ADDRESS, Constants.SERVICE_PORT, Constants.PASSWORD, pidFileManager, storageManager ); _service.Start(); }
public static int Main(string[] args) { // First line, hook the appdomain to the crash reporter AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; var waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset, "70a9f94f-59e8-4073-93ab-00aaacc26111", out var createdNew); if (!createdNew) { LOG.Error("Server process already started, please stop that server first."); return(2); } // Add the arguments supplied when running the application to the configuration var configSource = new ArgvConfigSource(args); // Commandline switches configSource.AddSwitch("Startup", "inifile"); configSource.AddSwitch("Startup", "logconfig"); configSource.AddSwitch("Startup", "pidfile"); configSource.AddSwitch("Startup", "purge"); var startupConfig = configSource.Configs["Startup"]; var pidFileManager = new PIDFileManager(startupConfig.GetString("pidfile", string.Empty)); // Configure Log4Net { var logConfigFile = startupConfig.GetString("logconfig", string.Empty); if (string.IsNullOrEmpty(logConfigFile)) { XmlConfigurator.Configure(); LogBootMessage(); LOG.Info("Configured log4net using ./WHIP_LRU.exe.config as the default."); } else { XmlConfigurator.Configure(new FileInfo(logConfigFile)); LogBootMessage(); LOG.Info($"Configured log4net using \"{logConfigFile}\" as configuration file."); } } // Configure nIni aliases and locale Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US", true); configSource.Alias.AddAlias("On", true); configSource.Alias.AddAlias("Off", false); configSource.Alias.AddAlias("True", true); configSource.Alias.AddAlias("False", false); configSource.Alias.AddAlias("Yes", true); configSource.Alias.AddAlias("No", false); var isRunning = true; WhipLru whipLru = null; // Handlers for signals. UnixSignal[] signals = null; if (ON_POSIX_COMPLAINT_OS) { signals = new [] { new UnixSignal(Signum.SIGINT), new UnixSignal(Signum.SIGTERM), new UnixSignal(Signum.SIGHUP), }; } else { Console.CancelKeyPress += (sender, cargs) => { LOG.Debug("CTRL-C pressed, terminating."); isRunning = false; whipLru?.Stop(); cargs.Cancel = true; waitHandle.Set(); }; } while (isRunning) { // Dump any known servers, we're going to reconfigure them. foreach (var server in _assetServersByName.Values) { server.Dispose(); } // TODO: might need to double buffer these, or something, so that old ones can finish out before being disposed. // Read in the ini file ReadConfigurationFromINI(configSource); // Read in a config list that lists the priority order of servers and their settings. var configRead = configSource.Configs["AssetsRead"]; var configWrite = configSource.Configs["AssetsWrite"]; var serversRead = GetServers(configSource, configRead, _assetServersByName); var serversWrite = GetServers(configSource, configWrite, _assetServersByName); var localStorageConfig = configSource.Configs["LocalStorage"]; var chattelConfigRead = GetConfig(localStorageConfig, serversRead); var chattelConfigWrite = GetConfig(localStorageConfig, serversWrite); var serverConfig = configSource.Configs["Server"]; var address = serverConfig?.GetString("Address", WHIPServer.DEFAULT_ADDRESS) ?? WHIPServer.DEFAULT_ADDRESS; var port = (uint?)serverConfig?.GetInt("Port", (int)WHIPServer.DEFAULT_PORT) ?? WHIPServer.DEFAULT_PORT; var password = serverConfig?.GetString("Password", WHIPServer.DEFAULT_PASSWORD); if (password == null) // Would only be null if serverConfig was null or DEFAULT_PASSWORD is null. Why not use the ?? operator? Compiler didn't like it. { password = WHIPServer.DEFAULT_PASSWORD; } var listenBacklogLength = (uint?)serverConfig?.GetInt("ConnectionQueueLength", (int)WHIPServer.DEFAULT_BACKLOG_LENGTH) ?? WHIPServer.DEFAULT_BACKLOG_LENGTH; var maxAssetLocalStorageDiskSpaceByteCount = (ulong?)localStorageConfig?.GetLong("MaxDiskSpace", (long)AssetLocalStorageLmdbPartitionedLRU.DB_MAX_DISK_BYTES_MIN_RECOMMENDED) ?? AssetLocalStorageLmdbPartitionedLRU.DB_MAX_DISK_BYTES_MIN_RECOMMENDED; var negativeCacheItemLifetime = TimeSpan.FromSeconds((uint?)localStorageConfig?.GetInt("NegativeCacheItemLifetimeSeconds", (int)StorageManager.DEFAULT_NC_LIFETIME_SECONDS) ?? StorageManager.DEFAULT_NC_LIFETIME_SECONDS); var partitionInterval = TimeSpan.FromMinutes((uint?)localStorageConfig?.GetInt("MinutesBetweenDatabasePartitions", (int)DEFAULT_DB_PARTITION_INTERVAL_MINUTES) ?? DEFAULT_DB_PARTITION_INTERVAL_MINUTES); var purgeAll = startupConfig.GetString("purge", string.Empty) == "all"; if (purgeAll) { LOG.Info("CLI request to purge all assets on startup specified."); } var readerLocalStorage = new AssetLocalStorageLmdbPartitionedLRU( chattelConfigRead, maxAssetLocalStorageDiskSpaceByteCount, partitionInterval ); var chattelReader = new ChattelReader(chattelConfigRead, readerLocalStorage, purgeAll); var chattelWriter = new ChattelWriter(chattelConfigWrite, readerLocalStorage, purgeAll); var storageManager = new StorageManager( readerLocalStorage, negativeCacheItemLifetime, chattelReader, chattelWriter ); whipLru = new WhipLru( address, port, password, pidFileManager, storageManager, listenBacklogLength ); whipLru.Start(); if (signals != null) { var signalIndex = UnixSignal.WaitAny(signals, -1); switch (signals[signalIndex].Signum) { case Signum.SIGHUP: whipLru.Stop(); break; case Signum.SIGINT: case Signum.SIGKILL: isRunning = false; whipLru.Stop(); break; default: // Signal unknown, ignore it. break; } } else { waitHandle.WaitOne(); } } foreach (var server in _assetServersByName.Values) { server.Dispose(); } return(0); }