事务性 CloudBlob
我使用 SQL Azure 来存储 Blob 元数据,使用 Azure Blob 存储来存储实际的 Blob。 Blob 创建/删除是通过在环境 TransactionScope 中登记这些操作来实现的。到目前为止,一切工作正常,但我想知道是否有人可以建议对删除操作进行优化(请参阅下面的源代码),这可能会消除下载 blob 内容以进行回滚的要求。
public class CloudBlobDeletionEnlistment : CloudBlobBaseEnlistment,
IEnlistmentNotification,
IDisposable
{
public CloudBlobDeletionEnlistment(Guid ownerId, string blobId, CloudBlobContainer container, Logger logger, IUserUploadActivity currentUploadActivity)
{
ctx = new Context { OwnerId = ownerId, BlobId = blobId, Container = container, Logger = logger, CurrentUploadActivity = currentUploadActivity };
}
public ~CloudBlobDeletionEnlistment()
{
Dispose(false);
}
public class Context
{
public Guid OwnerId;
public string BlobId;
public string ContentFileName;
public string MimeType;
public bool IsCompressed;
public CloudBlobContainer Container;
public Logger Logger;
public IUserUploadActivity CurrentUploadActivity;
}
private readonly Context ctx;
private CloudBlob blob;
public void Prepare(PreparingEnlistment preparingEnlistment)
{
blob = ctx.Container.GetBlobReference(ctx.BlobId);
// save backup information
ctx.ContentFileName = Path.GetTempFileName();
blob.DownloadToFile(ctx.ContentFileName);
blob.FetchAttributes();
ctx.MimeType = blob.Metadata[Constants.BlobMetaAttributeContentType];
ctx.IsCompressed = bool.Parse(blob.Metadata[Constants.BlobMetaAttributeCompressed]);
// delete it
blob.DeleteIfExists();
// done
preparingEnlistment.Prepared();
}
public void Commit(Enlistment enlistment)
{
Cleanup();
// done
enlistment.Done();
}
public void Rollback(Enlistment enlistment)
{
if (blob != null)
{
try
{
blob.UploadFile(ctx.ContentFileName);
blob.Metadata[Constants.BlobMetaAttributeContentType] = ctx.MimeType;
blob.Metadata[Constants.BlobMetaAttributeCompressed] = ctx.IsCompressed.ToString();
blob.SetMetadata();
}
finally
{
Cleanup();
}
}
else Cleanup();
// done
enlistment.Done();
}
public void InDoubt(Enlistment enlistment)
{
Cleanup();
enlistment.Done();
}
void Cleanup()
{
// delete the temporary file holding the blob content
if (!string.IsNullOrEmpty(ctx.ContentFileName) && File.Exists(ctx.ContentFileName))
{
File.Delete(ctx.ContentFileName);
ctx.ContentFileName = null;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// free managed resources
}
// free native resources if there are any.
Cleanup();
}
#endregion
}
I'm using SQL Azure for Blob Meta Data Storage and Azure Blob Storage for the actual blobs. Blob Creation/Deletion is implemented by enlisting those operation in the ambient TransactionScope. Everything works fine so far but I'm wondering if anyone can recommend optimizations to the Delete-Operation (see source code below) that might get-rid of the requirement to download the blob contents in order to rollback.
public class CloudBlobDeletionEnlistment : CloudBlobBaseEnlistment,
IEnlistmentNotification,
IDisposable
{
public CloudBlobDeletionEnlistment(Guid ownerId, string blobId, CloudBlobContainer container, Logger logger, IUserUploadActivity currentUploadActivity)
{
ctx = new Context { OwnerId = ownerId, BlobId = blobId, Container = container, Logger = logger, CurrentUploadActivity = currentUploadActivity };
}
public ~CloudBlobDeletionEnlistment()
{
Dispose(false);
}
public class Context
{
public Guid OwnerId;
public string BlobId;
public string ContentFileName;
public string MimeType;
public bool IsCompressed;
public CloudBlobContainer Container;
public Logger Logger;
public IUserUploadActivity CurrentUploadActivity;
}
private readonly Context ctx;
private CloudBlob blob;
public void Prepare(PreparingEnlistment preparingEnlistment)
{
blob = ctx.Container.GetBlobReference(ctx.BlobId);
// save backup information
ctx.ContentFileName = Path.GetTempFileName();
blob.DownloadToFile(ctx.ContentFileName);
blob.FetchAttributes();
ctx.MimeType = blob.Metadata[Constants.BlobMetaAttributeContentType];
ctx.IsCompressed = bool.Parse(blob.Metadata[Constants.BlobMetaAttributeCompressed]);
// delete it
blob.DeleteIfExists();
// done
preparingEnlistment.Prepared();
}
public void Commit(Enlistment enlistment)
{
Cleanup();
// done
enlistment.Done();
}
public void Rollback(Enlistment enlistment)
{
if (blob != null)
{
try
{
blob.UploadFile(ctx.ContentFileName);
blob.Metadata[Constants.BlobMetaAttributeContentType] = ctx.MimeType;
blob.Metadata[Constants.BlobMetaAttributeCompressed] = ctx.IsCompressed.ToString();
blob.SetMetadata();
}
finally
{
Cleanup();
}
}
else Cleanup();
// done
enlistment.Done();
}
public void InDoubt(Enlistment enlistment)
{
Cleanup();
enlistment.Done();
}
void Cleanup()
{
// delete the temporary file holding the blob content
if (!string.IsNullOrEmpty(ctx.ContentFileName) && File.Exists(ctx.ContentFileName))
{
File.Delete(ctx.ContentFileName);
ctx.ContentFileName = null;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// free managed resources
}
// free native resources if there are any.
Cleanup();
}
#endregion
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
对我来说,这似乎不是一个安全的回滚机制 - 上传可能会失败,如果发生这种情况,那么您的数据一致性就会被破坏。
如果您通过将 Blob 的名称放入数据库中的
ToBeDeleted
表中来删除 Blob,然后您设置一些常规作业时不时地删除这些 Blob,会怎么样?This doesn't seem like a safe rollback mechanism to me - the upload could fail and if that occurs then your data consistency would be broken.
What about if you delete your blobs by putting their names into a
ToBeDeleted
table in the database - and then you set up some regular job deletes these blobs from time to time?在我看来,您想要创建一个 blob 并在单个事务上下文中创建元数据。这是不可能的。您的程序逻辑必须“是事务”。
这同样适用于删除逻辑。
It looks to me like you want to create a blob and create metadata in a single transaction context. This is not possible. Your program logic must "be the transaction".
The same applies to delete logic.