mirror of
https://github.com/orbitdb/orbitdb.git
synced 2025-03-30 15:08:28 +00:00
Rework docs
This commit is contained in:
parent
f2d012b190
commit
c5cce8466c
107
docs/architecture.md
Normal file
107
docs/architecture.md
Normal file
@ -0,0 +1,107 @@
|
||||
***WIP***
|
||||
|
||||
### Structure
|
||||
The database has one log (OrbitList) for each *channel*. *Channel* is comparable to a *"topic"* or *"table"*.
|
||||
|
||||
```
|
||||
DB
|
||||
|-- channel 1
|
||||
| |-- list 1
|
||||
| | |-- node 1
|
||||
| | |-- operation
|
||||
| | |-- value
|
||||
| |-- list 2
|
||||
|-- channel 2
|
||||
|-- list 3
|
||||
...
|
||||
```
|
||||
|
||||
### Operation Logs
|
||||
- Each *channel* is saved as a log of operations: add, put, del
|
||||
- Operations are stored in an append-only log linked list
|
||||
- Each node in the linked list points to the previous node
|
||||
- Event log: take latest add or del operation for <hash>
|
||||
- JV-store: take last put or del operation for <key>
|
||||
|
||||
### CRDTs
|
||||
- orbit-db is a CmRDT and implements an LWW-element-set
|
||||
- operation-based CRDT
|
||||
- (locally biased) vector clocks for partial ordering
|
||||
|
||||
### add/put IO:
|
||||
==> Not expensive
|
||||
|
||||
1. Create POST for the content
|
||||
`ipfs object get QmZzic86oN7B5GMMYnTFvZMyDMjkKEBXe5SYsryXPeoGdb?`
|
||||
```json
|
||||
{
|
||||
"content": "hello 1",
|
||||
"ts": 1457703735759,
|
||||
"meta": {
|
||||
"type": "text",
|
||||
"size": 7,
|
||||
"ts": 1457703735759
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. Create POST for the DB operation
|
||||
`ipfs object get QmZzBNrUiYATJ4aicPTbupnEUWH3AHDmfBbDTQK3fhhYDE`
|
||||
```json
|
||||
{
|
||||
"op": "ADD",
|
||||
"key": "QmZzic86oN7B5GMMYnTFvZMyDMjkKEBXe5SYsryXPeoGdb",
|
||||
"value": "QmZzic86oN7B5GMMYnTFvZMyDMjkKEBXe5SYsryXPeoGdb",
|
||||
"meta": {
|
||||
"type": "orbit-db-op",
|
||||
"size": 15,
|
||||
"ts": 1457703735779
|
||||
},
|
||||
"by": "userA"
|
||||
}
|
||||
```
|
||||
|
||||
3. Create ipfs object for the nodet
|
||||
`ipfs object get QmX2Jq1JHmgjgM3YVuHyGSRpUWMDbv4PuRhqBhsZqDmagD`
|
||||
```json
|
||||
{
|
||||
"id": "userA",
|
||||
"seq": 0,
|
||||
"ver": 1,
|
||||
"data": "QmZzBNrUiYATJ4aicPTbupnEUWH3AHDmfBbDTQK3fhhYDE",
|
||||
"next": {
|
||||
"userA.0.0": "QmXUTgYPG4cSaHW8dKggJRfLvPWjaDktWyRAgn5NPwTqtz"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
4. Create ipfs object for the current list
|
||||
`ipfs object get Qmb2rpex9TdmoXvwLKLL24atWa2HfPbArobN7XiBAFvmZ9`
|
||||
```json
|
||||
{
|
||||
"id": "userA",
|
||||
"seq": 1,
|
||||
"ver": 0,
|
||||
"items": {
|
||||
"userA.0.0": "QmXUTgYPG4cSaHW8dKggJRfLvPWjaDktWyRAgn5NPwTqtz",
|
||||
"userA.0.1": "QmX2Jq1JHmgjgM3YVuHyGSRpUWMDbv4PuRhqBhsZqDmagD"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
5. Pubsub.publish (send to socket, network IO)
|
||||
```json
|
||||
{
|
||||
channel: '<channel name>',
|
||||
hash: 'Qmb2rpex9TdmoXvwLKLL24atWa2HfPbArobN7XiBAFvmZ9'
|
||||
}
|
||||
```
|
||||
|
||||
### get IO:
|
||||
==> A little expensive
|
||||
|
||||
1. Payload (get from ipfs-hash, network IO)
|
||||
|
||||
### sync/merge IO:
|
||||
==> Expensive!
|
||||
TODO
|
131
docs/ordering.md
Normal file
131
docs/ordering.md
Normal file
@ -0,0 +1,131 @@
|
||||
# Odering in OrbitList
|
||||
|
||||
```
|
||||
A B C
|
||||
0.0
|
||||
|
|
||||
0.0 0.1
|
||||
| |
|
||||
0.1 0.2
|
||||
\ / <--- Sync B with A and C
|
||||
1.0
|
||||
|
|
||||
1.1
|
||||
/ <--- Sync A with B
|
||||
2.0
|
||||
\
|
||||
\ <--- Sync C with A
|
||||
\
|
||||
3.0
|
||||
<--- Sync ALL
|
||||
```
|
||||
|
||||
Initial state:
|
||||
```
|
||||
A = []
|
||||
B = []
|
||||
C = []
|
||||
```
|
||||
|
||||
Two nodes add events concurrently:
|
||||
|
||||
Add items to A:
|
||||
```
|
||||
listA.add("mango")
|
||||
listA.add("banana")
|
||||
// "A": [
|
||||
// { "id": "A", "seq": 0, "ver": 0, "prev": null}
|
||||
// { "id": "A", "seq": 0, "ver": 1, "prev": ["A.0.0"]}
|
||||
// ]
|
||||
```
|
||||
|
||||
Add items to C:
|
||||
```
|
||||
listC.add("apple")
|
||||
listC.add("strawberry")
|
||||
listC.add("orange")
|
||||
// "C": [
|
||||
// { "id": "C", "seq": 0, "ver": 0, "prev": null}
|
||||
// { "id": "C", "seq": 0, "ver": 1, "prev": ["C.0.0"]}
|
||||
// { "id": "C", "seq": 0, "ver": 2, "prev": ["C.0.1"]}
|
||||
// ]
|
||||
```
|
||||
|
||||
B receives a 'sync' from A and C:
|
||||
```
|
||||
Sync: B <--> A
|
||||
Sync: B <--> C
|
||||
```
|
||||
|
||||
Add items to B:
|
||||
```
|
||||
listB.add("pineapple")
|
||||
listB.add("papaya")
|
||||
// "B": [
|
||||
// { "id": "A", "seq": 0, "ver": 0, "prev": null}
|
||||
// { "id": "A", "seq": 0, "ver": 1, "prev": ["A.0.0"]}
|
||||
// { "id": "C", "seq": 0, "ver": 0, "prev": null}
|
||||
// { "id": "C", "seq": 0, "ver": 1, "prev": ["C.0.0"]}
|
||||
// { "id": "C", "seq": 0, "ver": 2, "prev": ["C.0.1"]}
|
||||
// { "id": "B", "seq": 1, "ver": 0, "prev": ["A.0.1", "C.0.2"]}
|
||||
// { "id": "B", "seq": 1, "ver": 1, "prev": ["B.1.0"]}
|
||||
// ]
|
||||
```
|
||||
|
||||
A receives a 'sync' from B:
|
||||
```
|
||||
Sync: A <--> B
|
||||
```
|
||||
|
||||
```
|
||||
listA.add("kiwi")
|
||||
// "B": [
|
||||
// { "id": "A", "seq": 0, "ver": 0, "prev": null}
|
||||
// { "id": "A", "seq": 0, "ver": 1, "prev": ["A.0.0"]}
|
||||
// { "id": "C", "seq": 0, "ver": 0, "prev": null}
|
||||
// { "id": "C", "seq": 0, "ver": 1, "prev": ["C.0.0"]}
|
||||
// { "id": "C", "seq": 0, "ver": 2, "prev": ["C.0.1"]}
|
||||
// { "id": "B", "seq": 1, "ver": 0, "prev": ["A.0.1", "C.0.2"]}
|
||||
// { "id": "B", "seq": 1, "ver": 1, "prev": ["B.1.0"]}
|
||||
// { "id": "A", "seq": 2, "ver": 0, "prev": ["B.1.1"]}
|
||||
// ]
|
||||
```
|
||||
|
||||
C receives a 'sync' from A:
|
||||
```
|
||||
Sync: C <--> A
|
||||
```
|
||||
|
||||
```
|
||||
listC.add("blueberry")
|
||||
// "C": [
|
||||
// { "id": "A", "seq": 0, "ver": 0, "prev": null}
|
||||
// { "id": "A", "seq": 0, "ver": 1, "prev": ["A.0.0"]}
|
||||
// { "id": "C", "seq": 0, "ver": 0, "prev": null}
|
||||
// { "id": "C", "seq": 0, "ver": 1, "prev": ["C.0.0"]}
|
||||
// { "id": "C", "seq": 0, "ver": 2, "prev": ["C.0.1"]}
|
||||
// { "id": "B", "seq": 1, "ver": 0, "prev": ["A.0.1", "C.0.2"]}
|
||||
// { "id": "B", "seq": 1, "ver": 1, "prev": ["B.1.0"]}
|
||||
// { "id": "A", "seq": 2, "ver": 0, "prev": ["B.1.1"]}
|
||||
// { "id": "C", "seq": 3, "ver": 0, "prev": ["A.2.0"]}
|
||||
// ]
|
||||
```
|
||||
|
||||
A receives a 'sync' from C, B receives a 'sync' from C:
|
||||
```
|
||||
Sync: A <--> C
|
||||
Sync: B <--> C
|
||||
```
|
||||
|
||||
Data set converged (after sync ALL):
|
||||
```json
|
||||
{ "id": "A", "seq": 0, "ver": 0, "prev": null},
|
||||
{ "id": "A", "seq": 0, "ver": 1, "prev": ["A.0.0"]},
|
||||
{ "id": "C", "seq": 0, "ver": 0, "prev": null},
|
||||
{ "id": "C", "seq": 0, "ver": 1, "prev": ["C.0.0"]},
|
||||
{ "id": "C", "seq": 0, "ver": 2, "prev": ["C.0.1"]},
|
||||
{ "id": "B", "seq": 1, "ver": 0, "prev": ["A.0.1", "C.0.2"]},
|
||||
{ "id": "B", "seq": 1, "ver": 1, "prev": ["B.1.0"]}
|
||||
{ "id": "A", "seq": 2, "ver": 0, "prev": ["B.1.1"]}
|
||||
{ "id": "C", "seq": 3, "ver": 0, "prev": ["A.2.0]"]}
|
||||
```
|
@ -1,149 +0,0 @@
|
||||
// Data set grouped and sorted
|
||||
"A" : [
|
||||
{ "id": "A", "seq": 0, "ver": 0, "prev": null},
|
||||
{ "id": "A", "seq": 0, "ver": 1, "prev": "A0.0"},
|
||||
{ "id": "A", "seq": 0, "ver": 2, "prev": "A0.1"},
|
||||
{ "id": "A", "seq": 0, "ver": 3, "prev": "A0.2"},
|
||||
{ "id": "A", "seq": 0, "ver": 4, "prev": "A0.3"},
|
||||
{ "id": "A", "seq": 2, "ver": 0, "prev": ["A0.4", "B1.1"]}
|
||||
],
|
||||
"B" : [
|
||||
{ "id": "B", "seq": 1, "ver": 0, "prev": ["A0.4", "C0.2"]},
|
||||
{ "id": "B", "seq": 1, "ver": 1, "prev": "B1.0"}
|
||||
],
|
||||
"C" : [
|
||||
{ "id": "C", "seq": 0, "ver": 0, "prev": null},
|
||||
{ "id": "C", "seq": 0, "ver": 1, "prev": "C0.0"},
|
||||
{ "id": "C", "seq": 0, "ver": 2, "prev": "C0.1"},
|
||||
{ "id": "C", "seq": 3, "ver": 0, "prev": ["C0.2", "A2.0]"]}
|
||||
]
|
||||
|
||||
A B C
|
||||
|
|
||||
0.0
|
||||
|
|
||||
0.1
|
||||
|
|
||||
0.2 0.0
|
||||
| |
|
||||
0.3 0.1
|
||||
| |
|
||||
0.4 0.2
|
||||
| \ / |
|
||||
| 1.0 |
|
||||
| | |
|
||||
| 1.1 |
|
||||
| / |
|
||||
2.0 |
|
||||
\ |
|
||||
\ |
|
||||
\ |
|
||||
3.0
|
||||
|
||||
// expected order A
|
||||
{ "id": "A", "seq": 0, "ver": 0, "prev": null},
|
||||
{ "id": "A", "seq": 0, "ver": 1, "prev": "A0.0"},
|
||||
{ "id": "A", "seq": 0, "ver": 2, "prev": "A0.1"},
|
||||
{ "id": "A", "seq": 0, "ver": 3, "prev": "A0.2"},
|
||||
{ "id": "A", "seq": 0, "ver": 4, "prev": "A0.3"},
|
||||
{ "id": "C", "seq": 0, "ver": 0, "prev": null},
|
||||
{ "id": "C", "seq": 0, "ver": 1, "prev": "C0.0"},
|
||||
{ "id": "C", "seq": 0, "ver": 2, "prev": "C0.1"},
|
||||
{ "id": "B", "seq": 1, "ver": 0, "prev": ["A0.4", "C0.2"]},
|
||||
{ "id": "B", "seq": 1, "ver": 1, "prev": "B1.0"}
|
||||
{ "id": "A", "seq": 2, "ver": 0, "prev": ["A0.4", "B1.1"]}
|
||||
{ "id": "C", "seq": 3, "ver": 0, "prev": ["C0.2", "A2.0]"]}
|
||||
|
||||
"VersionClock": {
|
||||
"seq": 0,
|
||||
"ver": 0
|
||||
}
|
||||
|
||||
"Item": {
|
||||
"id": "",
|
||||
"VersionClock": "<VersionClock>",
|
||||
"prev": []
|
||||
}
|
||||
|
||||
"List": {
|
||||
"items": ["<Item>"]
|
||||
}
|
||||
|
||||
|
||||
A B C
|
||||
0.0
|
||||
|
|
||||
0.0 0.1
|
||||
| |
|
||||
0.1 0.2
|
||||
\ / |
|
||||
1.0 |
|
||||
| |
|
||||
1.1 |
|
||||
/ |
|
||||
2.0 |
|
||||
\ |
|
||||
\ |
|
||||
\ |
|
||||
3.0
|
||||
|
||||
// Sequence, --> syncs to
|
||||
listA.add("mango") // { "id": "A", "seq": 0, "ver": 0, "prev": null}
|
||||
listA.add("banana") // { "id": "A", "seq": 0, "ver": 1, "prev": "A.0.0"}
|
||||
--> B
|
||||
|
||||
// A
|
||||
// { "id": "A", "seq": 0, "ver": 0, "prev": null}
|
||||
// { "id": "A", "seq": 0, "ver": 1, "prev": "A.0.0"}
|
||||
|
||||
listC.add("apple") // { "id": "C", "seq": 0, "ver": 0, "prev": null}
|
||||
listC.add("strawberry") // { "id": "C", "seq": 0, "ver": 1, "prev": "C.0.0"}
|
||||
listC.add("orange") // { "id": "C", "seq": 0, "ver": 2, "prev": "C.0.1"}
|
||||
--> A,B
|
||||
|
||||
// A
|
||||
// { "id": "A", "seq": 0, "ver": 0, "prev": null}
|
||||
// { "id": "A", "seq": 0, "ver": 1, "prev": "A.0.0"}
|
||||
// { "id": "C", "seq": 0, "ver": 0, "prev": null}
|
||||
// { "id": "C", "seq": 0, "ver": 1, "prev": "C.0.0"}
|
||||
// { "id": "C", "seq": 0, "ver": 2, "prev": "C.0.1"}
|
||||
|
||||
listB.add("pineapple") // { "id": "B", "seq": 1, "ver": 0, "prev": ["A.0.1", "C.0.2"]}
|
||||
listB.add("papaya") // { "id": "B", "seq": 1, "ver": 1, "prev": "B.1.0"}
|
||||
--> A
|
||||
|
||||
// A
|
||||
// { "id": "A", "seq": 0, "ver": 0, "prev": null}
|
||||
// { "id": "A", "seq": 0, "ver": 1, "prev": "A.0.0"}
|
||||
// { "id": "C", "seq": 0, "ver": 0, "prev": null}
|
||||
// { "id": "C", "seq": 0, "ver": 1, "prev": "C.0.0"}
|
||||
// { "id": "C", "seq": 0, "ver": 2, "prev": "C.0.1"}
|
||||
// { "id": "B", "seq": 1, "ver": 0, "prev": ["A.0.1", "C.0.2"]}
|
||||
// { "id": "B", "seq": 1, "ver": 1, "prev": "B.1.0"}
|
||||
|
||||
listA.add("kiwi") // { "id": "A", "seq": 2, "ver": 0, "prev": ["A.0.1", "B1.1", "C0.2"]}
|
||||
--> C
|
||||
|
||||
// A
|
||||
// { "id": "A", "seq": 0, "ver": 0, "prev": null}
|
||||
// { "id": "A", "seq": 0, "ver": 1, "prev": "A.0.0"}
|
||||
// { "id": "C", "seq": 0, "ver": 0, "prev": null}
|
||||
// { "id": "C", "seq": 0, "ver": 1, "prev": "C.0.0"}
|
||||
// { "id": "C", "seq": 0, "ver": 2, "prev": "C.0.1"}
|
||||
// { "id": "B", "seq": 1, "ver": 0, "prev": ["A.0.0", "C.0.2"]}
|
||||
// { "id": "B", "seq": 1, "ver": 1, "prev": "B.1.0"}
|
||||
// { "id": "A", "seq": 2, "ver": 0, "prev": ["A.0.1", "B1.1", "C0.2"]}
|
||||
|
||||
listC.add("blueberry") // { "id": "C", "seq": 3, "ver": 0, "prev": ["A.2.0", "C.0.2"]}
|
||||
--> A,B
|
||||
|
||||
// A
|
||||
// { "id": "A", "seq": 0, "ver": 0, "prev": null}
|
||||
// { "id": "A", "seq": 0, "ver": 1, "prev": "A.0.0"}
|
||||
// { "id": "C", "seq": 0, "ver": 0, "prev": null}
|
||||
// { "id": "C", "seq": 0, "ver": 1, "prev": "C.0.0"}
|
||||
// { "id": "C", "seq": 0, "ver": 2, "prev": "C.0.1"}
|
||||
// { "id": "B", "seq": 1, "ver": 0, "prev": ["A.0.0", "C.0.2"]}
|
||||
// { "id": "B", "seq": 1, "ver": 1, "prev": "B.1.0"}
|
||||
// { "id": "A", "seq": 2, "ver": 0, "prev": ["A.0.1", "B1.1", "C0.2"]}
|
||||
// { "id": "C", "seq": 3, "ver": 0, "prev": ["A.2.0", "C.0.2"]}
|
Loading…
x
Reference in New Issue
Block a user