/// <summary> /// Thread safe, runs on own thread for data lock. /// </summary> /// <param name="account"></param> /// <returns></returns> public static async Task Save(AccountDataItem account) { using (MemoryStream stream = new MemoryStream()) { // Serialize on current thread GetSerializer().WriteObject(stream, account); stream.Position = 0; await Task.Run(async delegate { using (await Locks.LockAccounts()) { // Get the account folder var timeTracker = TimeTracker.Start(); IFolder accountFolder = await FileHelper.GetOrCreateAccountFolder(account.LocalAccountId); timeTracker.End(3, "AccountsManager.Save GetOrCreateAccountFolder"); // Create a temp file to write to timeTracker = TimeTracker.Start(); IFile tempAccountFile = await accountFolder.CreateFileAsync("TempAccountData.dat", CreationCollisionOption.ReplaceExisting); timeTracker.End(3, "AccountsManager.Save creating temp file"); // Write the data to the temp file timeTracker = TimeTracker.Start(); using (Stream s = await tempAccountFile.OpenAsync(StorageEverywhere.FileAccess.ReadAndWrite)) { timeTracker.End(3, "AccountsManager.Save opening file stream"); timeTracker = TimeTracker.Start(); stream.CopyTo(s); timeTracker.End(3, "AccountsManager.Save copying stream to file"); } // Move the temp file to the actual file timeTracker = TimeTracker.Start(); await tempAccountFile.RenameAsync(FileNames.ACCOUNT_FILE_NAME, NameCollisionOption.ReplaceExisting); timeTracker.End(3, "AccountsManager.Save renaming temp file to final"); } }); } }
private static async Task <AccountDataItem> GetOrLoadHelper(Guid localAccountId) { Debug.WriteLine("GetOrLoad Account: " + localAccountId); CachedAccountEntry entry; lock (_cachedAccounts) { if (!_cachedAccounts.TryGetValue(localAccountId, out entry)) { entry = new CachedAccountEntry(); _cachedAccounts[localAccountId] = entry; } // Cache entry exists else { // But account still might have been disposed var account = entry.Account; if (account != null) { Debug.WriteLine("Returning cached account: " + localAccountId); return(account); } } } Debug.WriteLine("GetOrLoad Account starting thread to enter data lock: " + localAccountId); // We'll have to enter a lock and then load it (if it's not already loaded at that point) return(await System.Threading.Tasks.Task.Run(async delegate { Debug.WriteLine("GetOrLoad Account acquiring lock: " + localAccountId); using (await Locks.LockAccounts()) { Debug.WriteLine("GetOrLoad Account acquired lock: " + localAccountId); AccountDataItem account; // Double check if account's already loaded (might have been loaded by the time we've entered the lock) account = entry.Account; if (account != null) { Debug.WriteLine("GetOrLoad Account, account already loaded: " + localAccountId); return account; } Debug.WriteLine("Loading account: " + localAccountId); account = await Load(localAccountId); // If account doesn't exist if (account == null) { Debug.WriteLine("Account didn't exist: " + localAccountId); return null; } Debug.WriteLine("Loaded account: " + localAccountId); entry.Account = account; return account; } })); }