我们的系统中有一个叫做“身份程序”的实体。这也是我们的切分边界,每个标识程序都存储在自己的碎片中,所以碎片的标识符就是标识程序的标识符。
我们正在实施实际删除身份程序的能力。作为这一过程的一部分,我们希望清理碎片地图。为此,我写了以下几篇文章:
var shardKey = new Guid("E03F1DC0-5CA9-45AE-B6EC-0C90529C0062");
var connectionString = @"shard-catalog-connection-string";
var shardMapManager = ShardMapManagerFactory.GetSqlShardMapManager(connectionString, ShardMapManagerLoadPolicy.Lazy);
var shardMap = shardMapManager.GetListShardMap<Guid>("IdentityProgramIdListShardMap");
if (shardMap.TryGetMappingForKey(shardKey, out PointMapping<Guid> mapping))
{
if (mapping.Status == MappingStatus.Online)
{
shardMap.MarkMappingOffline(mapping);
}
shardMap.DeleteMapping(mapping);
}问题是,当它到达DeleteMapping调用时,它会得到一个异常:
ShardManagementException:在碎片映射'IdentityProgramIdListShardMap‘中引用碎片' shard -connection-string’的映射不存在。为操作“RemovePointMapping”执行存储过程'__ShardManagement.spBulkOperationShardMappingsGlobalBegin‘时发生错误。如果另一个并发用户已经删除了映射,则可能发生这种情况。
但是映射还没有被删除,因为在那之后我执行:
mappings = shardMap.GetMappings();
foreach(var mapping in mappings)
{
Console.WriteLine(mapping.Value);
}我可以看到,shardmap条目仍然在那里,并且被标记为脱机。
如果删除对MarkMappingOffline的调用,就会得到一个异常,说明碎片映射不能被删除,因为它是联机的。
所以我好像抓到了-22。如果我离线标记它,它会认为碎片映射已经消失,并且不允许我删除它。如果我不把它标记为离线,它会告诉我它必须离线。
发布于 2017-10-17 00:20:04
您必须始终对映射的当前版本进行操作,所以代码应该是
if (shardMap.TryGetMappingForKey(shardKey, out PointMapping<Guid> mapping))
{
if (mapping.Status == MappingStatus.Online)
{
// `mapping =` on next line is needed
mapping = shardMap.MarkMappingOffline(mapping);
}
shardMap.DeleteMapping(mapping);
}为了进一步解释:弹性db工具使用了一个乐观的并发模型,其中每个操作都检查您对每个对象的最新版本进行操作。错误消息是说对映射进行了“并发”修改,即在得到映射之后,但在执行DeleteMapping之前,其他人并发地执行了DeleteMapping。实际上,“其他人”就是你自己,但是因为你没有删除最新版本的映射,弹性数据库工具没有意识到它就是你。:)
https://stackoverflow.com/questions/46779549
复制相似问题