Ejemplo n.º 1
0
        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
                );
        }
Ejemplo n.º 2
0
        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();
        }
Ejemplo n.º 3
0
        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();
        }
Ejemplo n.º 4
0
        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);
            }
        }
Ejemplo n.º 5
0
        [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);
        }
Ejemplo n.º 6
0
        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);
            }
        }
Ejemplo n.º 7
0
        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);
        }
Ejemplo n.º 8
0
        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);
        }
Ejemplo n.º 9
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));

            // 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();
        }
Ejemplo n.º 10
0
        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);
        }
Ejemplo n.º 11
0
        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();
        }
Ejemplo n.º 13
0
        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);
        }
Ejemplo n.º 14
0
        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();
        }
Ejemplo n.º 15
0
        [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);
        }
Ejemplo n.º 16
0
        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);
        }
Ejemplo n.º 17
0
        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);
        }
Ejemplo n.º 18
0
        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],
            });
        }
Ejemplo n.º 19
0
        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);
        }
Ejemplo n.º 20
0
        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);
        }
Ejemplo n.º 21
0
        /// <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,
                };
            }
        }
Ejemplo n.º 22
0
        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();
        }
Ejemplo n.º 23
0
        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);
        }
Ejemplo n.º 24
0
        [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);
        }
Ejemplo n.º 25
0
        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);
        }
Ejemplo n.º 27
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);
        }
Ejemplo n.º 28
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();
        }
Ejemplo n.º 29
0
        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);
        }