public async Task ReplaceRelativePathAndUpdateLastDeletion(ICacheDatabaseRecord record, string movedRelativePath, DateTime lastDeletionAttempt) { var newRecord = new CacheDatabaseRecord() { AccessCountKey = record.AccessCountKey, ContentType = record.ContentType, CreatedAt = record.CreatedAt, DiskSize = record.DiskSize, LastDeletionAttempt = lastDeletionAttempt, RelativePath = movedRelativePath }; var loadedDict = await GetLoadedDict(); if (loadedDict.TryAdd(movedRelativePath, newRecord)) { await writeLog.LogCreated(newRecord); } else { throw new InvalidOperationException("Record already moved in database"); } await DeleteRecord(record); }
public Task DeleteRecord(int shard, ICacheDatabaseRecord record) { if (record.CreatedAt > DateTime.UtcNow) { throw new InvalidOperationException(); } return(shards[shard].DeleteRecord(record)); }
public LogEntry(LogEntryType entryType, ICacheDatabaseRecord record) { EntryType = entryType; AccessCountKey = record.AccessCountKey; ContentType = record.ContentType; RelativePath = record.RelativePath; DiskSize = record.DiskSize; LastDeletionAttempt = record.LastDeletionAttempt; CreatedAt = record.CreatedAt; }
/// <summary> /// Skips the record if there is delete contention for a file. /// Only counts bytes as deleted if the physical file is deleted successfully. /// Deletes db record whether file exists or not. /// </summary> /// <param name="shard"></param> /// <param name="record"></param> /// <param name="writeLocks"></param> /// <returns></returns> private async Task <long> TryDeleteRecord(int shard, ICacheDatabaseRecord record, AsyncLockProvider writeLocks) { long bytesDeleted = 0; var unused = await writeLocks.TryExecuteAsync(record.RelativePath, 0, CancellationToken.None, async() => { var physicalPath = PathBuilder.GetPhysicalPathFromRelativePath(record.RelativePath); try { if (File.Exists(physicalPath)) { File.Delete(physicalPath); await Database.DeleteRecord(shard, record); bytesDeleted = record.DiskSize; } else { await Database.DeleteRecord(shard, record); } } catch (IOException ioException) { if (physicalPath.Contains(".moving_")) { // We already moved it. All we can do is update the last deletion attempt await Database.UpdateLastDeletionAttempt(shard, record.RelativePath, DateTime.UtcNow); return; } var movedRelativePath = record.RelativePath + ".moving_" + new Random().Next(int.MaxValue).ToString("x", CultureInfo.InvariantCulture); var movedPath = PathBuilder.GetPhysicalPathFromRelativePath(movedRelativePath); try { //Move it so it usage will decrease and it can be deleted later //TODO: This is not transactional, as the db record is written *after* the file is moved //This should be split up into create and delete (Options.MoveFileOverwriteFunc ?? File.Move)(physicalPath, movedPath); await Database.ReplaceRelativePathAndUpdateLastDeletion(shard, record, movedRelativePath, DateTime.UtcNow); Logger?.LogError(ioException, "HybridCache: Error deleting file, moved for eventual deletion - {Path}", record.RelativePath); } catch (IOException ioException2) { await Database.UpdateLastDeletionAttempt(shard, record.RelativePath, DateTime.UtcNow); Logger?.LogError(ioException2, "HybridCache: Failed to move file for eventual deletion - {Path}", record.RelativePath); } } }); return(bytesDeleted); }
public async Task DeleteRecord(ICacheDatabaseRecord oldRecord) { using (await createLock.LockAsync()) { if ((await GetLoadedDict()).TryRemove(oldRecord.RelativePath, out var currentRecord)) { if (currentRecord != oldRecord) { logger?.LogError( "DeleteRecord tried to delete a different instance of the record than the one provided. Re-inserting in {ShardId}", shardId); (await GetLoadedDict()).TryAdd(oldRecord.RelativePath, currentRecord); } else { await writeLog.LogDeleted(oldRecord); } } } }
public Task LogDeleted(ICacheDatabaseRecord deletedRecord) { return(WriteLogEntry(new LogEntry(LogEntryType.Delete, deletedRecord), false)); }
public Task ReplaceRelativePathAndUpdateLastDeletion(int shard, ICacheDatabaseRecord record, string movedRelativePath, DateTime lastDeletionAttempt) { return(shards[shard].ReplaceRelativePathAndUpdateLastDeletion(record, movedRelativePath, lastDeletionAttempt)); }