AntidoteDB / AntidoteDB/antidote

RFC 100: Public API for information on synchronization

未关闭
#318 11 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
feature-request
主要语言
Erlang
星标
892
派生
92
PR 合并指标
30 天内没有已合并 PR

描述

# RFC 100: Public API for information on synchronization

_Authors:_ Nuno Preguiça, Gonçalo Cabrita, Jean Araújo

_Status:_ Under discussion
(Under discussion / Rejected / Approved: assigned to X / Implemented: pull request X)

## Context and Goal

### Context

In AntidoteDB, updates are propagated asynchronously among DCs. A transaction accesses a snapshot of the stable updates known at the local DC (with stable meaning that atomicity of updates in a transaction and causal dependencies across transactions are satisfied).

Thus, when a transaction reads a value in a DC, it is possible some updates to that value have already been committed in some other DCs. Additionally, during the execution of a transaction, some other transaction may modify the read value in the same (or other) DC -- these updates are also not visible to the running transaction.

### Goal

Provide an API to allow applications to have information about the up-to-date'ness of read data. This allows the application to reason about the staleness of read data, based on information available in the local DC.

We can define _potential staleness_ as the time period for which the read data may be stale. This can be computed from the last synchronization with remote DCs, which establish the earliest time when an unseen update may have been issued (at some other DC).

## Use Case

### Synchronization status

A user-facing application may want to provide information to the user on the last time the local replica has been synchronized with the remote DCs.

### Information on known changes

An application may want to prevent executing transactions on data that it knows has been modified concurrently.

## API changes

### External: AntidoteDB + protobuf

- `last_sync([bound_object()], TxId) -> {ok, [clock_time()]}`.
For each object, it returns the earliest time it synchronized for the last time with some DC replicating the object -- let _t1_ be the last time it synchronized with DC 1, the result for object _o_ is _min(ti)_, with i the DCs where _o_ is replicated.

- `last_sync_detail([bound_object()], TxId) -> {ok, [vectorclock()]}`.
The same as before, but detailing the information of last synchronization with each DC.

- `known_stale([bound_object()], TxId) -> {ok, [boolean()]}`.
For each data item, it returns whether the local DC has received an update that has not been reflected in the transaction snapshot.

### Internal: transaction manager

- `last_sync([bound_object()], TxId) -> {ok, [clock_time()]}`.
- `last_sync_detail([bound_object()], TxId) -> {ok, [vectorclock()]}`.
- `known_stale([bound_object()], TxId) -> {ok, [boolean()]}`.
As in the external API.

### Internal: log

- `has_new_updates([bound_object(),vectorclock()]) -> {ok, [integer()]}`.
Returns the number of known updates not reflects in the given vectorclock.

## Design

- `last_sync([bound_object()], TxId) -> {ok, [clock_time()]}`.

The return value can be computed from the snapshot time of the transaction. It is only necessary to process the operation in the component that records the snapshot time for the transaction.

```
API.last_sync([bound_object()], TxId) ->
TM.last_sync([bound_object()], TxId).

TM.last_sync( list, TxId) ->
snapshot_time = get_snapshot_time( TxId)
return {ok, list.map(key ->
replicas = get_replica_set( key)
min( snapshot_time.filter( replicas)) ) }
```

NOTE: this implementation supports partial replication.

- `last_sync_detail([bound_object()], TxId) -> {ok, [vectorclock()]}`.

The return value can be computed from the snapshot time of the transaction. It is only necessary to process the operation in the component that records the snapshot time for the transaction.

```
API.last_sync_detail([bound_object()], TxId) ->
TM.last_sync_detail([bound_object()], TxId).

TM.last_sync_detail( list, TxId) ->
snapshot_time = get_snapshot_time( TxId)
return {ok, list.map(key ->
replicas = get_replica_set( key)
snapshot_time.filter( replicas) ) }
```

- `known_stale([bound_object()], TxId) -> {ok, [boolean()]}`.

```
API.known_stale([bound_object()], TxId) ->
TM.known_stale([bound_object()], TxId).

TM.known_stale([bound_object()], TxId) ->
snapshot_time = get_snapshot_time( TxId)
return {ok, list.map(key ->
LOG.has_new_updates([key,snapshot_time] > 0) ) }
```

- `LOG.has_new_updates([bound_object(),vectorclock()]) -> {ok, [integer()]}`.

Return value based on the log information.

## Implementation

Straightforward from the design.

Propagate calls to `clocksi_readitem_server` (the same way a read is done), where the snapshot time of the transaction is known.

## Prior discussion

This feature has been discussed in the past in:
- Syncfree deliverable D3.2 [https://syncfree.lip6.fr/attachments/article/46/d3.2.pdf]
- Deepthi Devaki Akkoorath, Viktória Fördós, Annette Bieniusa: Observing the consistency of distributed systems. Erlang Workshop 2016: 54-55.

## Record of changes

04-10-2017: first complete version

贡献指南

这个仓库没有索引到贡献指南

评估

这个 Issue 还没有评估数据。

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。