public (User[], AssetsCache, CompactFinTimeSeries <DateOnly, uint, float, uint>) GetAssuredConsistentTables() { // if client wants to be totally secure and consistent when getting subtables MemData localMemData = m_memData; // if m_memData swap occurs, that will not ruin our consistency return(localMemData.Users, localMemData.AssetsCache, localMemData.DailyHist); }
async Task ReloadDbDataIfChangedImpl() // if necessary it reloads Historical and Realtime data { Console.WriteLine("*MemDb is not yet ready! ReloadDbData is in progress..."); DateTime startTime = DateTime.UtcNow; // GA.IM.NAV assets have user_id data, so User data has to be reloaded too before Assets (bool isDbReloadNeeded, User[]? newUsers, List <Asset>?sqCoreAssets) = m_Db.GetDataIfReloadNeeded(); if (!isDbReloadNeeded) { return; } // to minimize the time memDb is not consintent we create everything into new pointers first, then update them quickly var newAssetCache = AssetsCache.CreateAssetCache(sqCoreAssets !); // var newPortfolios = GeneratePortfolios(); if (IsInitialized) { // if this is the periodic (not initial) reload of RedisDb, then we don't surprise clients by emptying HistPrices // and not having HistPrices for 20minutes. So, we download HistPrices before swapping m_memData pointer DateTime startTimeHist = DateTime.UtcNow; var newDailyHist = await CreateDailyHist(m_Db, newUsers !, newAssetCache); // downloads historical prices from YF. Assume it takes 20min if (newDailyHist == null) { newDailyHist = new CompactFinTimeSeries <DateOnly, uint, float, uint>(); } m_lastHistoricalDataReload = DateTime.UtcNow; m_lastHistoricalDataReloadTs = DateTime.UtcNow - startTimeHist; var newMemData = new MemData(newUsers !, newAssetCache, newDailyHist); m_memData = newMemData; // swap pointer in atomic operation Console.WriteLine($"*MemDb is ready! (#Assets: {AssetsCache.Assets.Count}, #HistoricalAssets: {DailyHist.GetDataDirect().Data.Count}) in {m_lastHistoricalDataReloadTs.TotalSeconds:0.000}sec"); } else { // if this is the first time to load DB from Redis, then we don't demand HistData. Assume HistData crawling takes 20min // many clients can survive without historical data first. MarketDashboard. However, they need Asset and User data immediately. // BrAccInfo is fine wihout historical. It will send NaN as a LastClose. Fine. Client will handle it. // So, we don't need to wait for Historical to finish InitDb (that might take 20 minutes in the future). // !!! Also, in development, we don't want to wait until All HistData arrives, but start Debugging code right away after starting the WebServer. // Clients of MemDb should handle properly if HistData is not yet ready (NaN and later Refresh). var newMemData = new MemData(newUsers !, newAssetCache, new CompactFinTimeSeries <DateOnly, uint, float, uint>()); m_memData = newMemData; // swap pointer in atomic operation Console.WriteLine($"*MemDb is half-ready! (#Assets: {AssetsCache.Assets.Count}, #HistoricalAssets: 0)"); } m_lastDbReload = DateTime.UtcNow; m_lastDbReloadTs = DateTime.UtcNow - startTime; foreach (var brAccount in BrAccounts) { UpdateBrAccPosAssetIds(brAccount.AccPoss); } OnReloadAssetData_ReloadRtDataAndSetTimer(); // downloads realtime prices from YF or IEX OnReloadAssetData_ReloadRtNavDataAndSetTimer(); // downloads realtime NAVs from VBrokers EvDbDataReloaded?.Invoke(); }