在 Datomic 中需要泛化比较和交换语义的情况下如何设计?

Posted

技术标签:

【中文标题】在 Datomic 中需要泛化比较和交换语义的情况下如何设计?【英文标题】:How to design at the situation that we need generalized compare-and-swap semantic in Datomic? 【发布时间】:2019-04-16 10:51:26 【问题描述】:

我的问题是这样的:

我需要使用 Datomic 来建模:

    用户可以提出请求。最初,请求处于打开状态。 管理员可以批准/拒绝/修改用户请求。

请求架构如下:

:req/status     ;; cardinality one. It can be: open, modified, approved, rejected
:req/things     ;; cardinality many. [thing-id ...] 

管理员可以看到来自 Web 应用程序 UI 的用户请求。管理员有三个选项:批准、拒绝、修改。如果请求被批准或拒绝,则该请求不再有效。它将从管理 UI 中消失。但是,如果请求被修改,它仍然可以被批准、被拒绝或再次修改。修改请求时,只能修改req/things。在这个系统中,可能有多个管理员同时对同一个请求进行操作。

请求状态的状态图为:

 open -> modified 
 modified -> modified 
 modified, open -> approved (done)
 modified, open -> rejected (done)

考虑一种情况: 两个管理员 A 和 B 处理同一个请求,但他们没有感知到对方。他们同时按下按钮。一位管理员 A 批准该请求,另一位管理员 B 修改该请求。该请求最初是在之前修改过的,所以在两个管理员处理它时它的状态为modified

系统的正确行为可能有两种可能:管理员 A 操作成功或管理员 B 操作成功。如果admin A先操作成功,则不能再修改请求。如果admin B先操作成功,那么A的审批应该不会发生,因为req/things已经被修改了,但是admin A审批了另外一组req/things

我考虑使用db.fn/cas 来保证admin A 或admin B 只有一次操作可以成功。但是,db.fn/cas 不适用于许多基数。

目前,我认为有两种方法可以解决我的问题(只有一个操作可以成功):

添加一个额外的架构req/stamp 到 req. 戳记初始为0,每次操作都会增加1。然后我可以使用这个戳记和db.fn/cas来保证操作的逻辑严格性。

安装一些自定义的db函数,如this,可以对基数做CAS,保证逻辑上的严格性。

我很好奇在 Datomic 中哪种方式更规范地解决这个问题,或者还有另一种方式来解决这种问题?

【问题讨论】:

我发现 Mongoose 从版本 3 开始有一个类似的设计,叫做versionKey,对应我原来问题中的req/stamp 【参考方案1】:

绝对不是专家,但我认为在此用例中引入时间戳并在事务中进行比较更简单。

【讨论】:

以上是关于在 Datomic 中需要泛化比较和交换语义的情况下如何设计?的主要内容,如果未能解决你的问题,请参考以下文章

Datomic 中的数据建模

UML语言体系

UML语言体系

Datomic 与 Neo4j 相比如何?

使用策略相似性嵌入改进强化学习的泛化

神经网络学习之泛化能力的提高