Skip to content

Commit 15e9f1e

Browse files
author
gas
committed
README finished
1 parent 2a12280 commit 15e9f1e

File tree

2 files changed

+36
-9
lines changed

2 files changed

+36
-9
lines changed

README.md

+34-9
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,44 @@
1-
![main tests](https://github.com/gasparian/logical-clocks/actions/workflows/test.yml/badge.svg?branch=main)
1+
![main tests](https://github.com/gasparian/logical-clocks/actions/workflows/test.yml/badge.svg?branch=main)
22

33
# logical-clocks
4-
Go implementation of several clocks types: Lamport, Vector and Hybrid Logical Clock
4+
In the distributed systems there is a problem of defining casual order of events. Usually you need that to implement MVCC or CRDTs. And you can't always rely only on physical clocks since it is very hard to achieve tight clocks synchronization in real world.
5+
But there is a very "elegant" solution to that: use logical clocks, where we can also rely on counting events occuring in the system.
6+
So here you will find my naive go implementation of three basic logical clocks types: [Lamport clock](https://lamport.azurewebsites.net/pubs/time-clocks.pdf), [Vector clock](https://fileadmin.cs.lth.se/cs/Personal/Amr_Ergawy/dist-algos-papers/4.pdf) and [Hybrid logical clock](https://cse.buffalo.edu/tech-reports/2014-04.pdf).
57

68
## Usage
7-
Run `make init` to place pre-commit hook in `.git` folder.
9+
Run `make init` to replace pre-commit hook into `.git` folder.
810
To test the clocks implementations run `make test`.
11+
Getting the package:
12+
```
13+
go get github.com/gasparian/logical-clocks
14+
```
915

10-
*TODO*
16+
Then you can start using clocks:
17+
```go
18+
import (
19+
hlc "github.com/gasparian/logical-clocks/hlc"
20+
)
21+
22+
// Instantiate hybrid clock with the current wall clock timestamp
23+
hc := hlc.NewNow(0)
24+
// ...handle request from other service
25+
req := ...
26+
// Apply tick using the hybrid timestamp that came from another service
27+
hc.Tick(req.Time)
28+
// Get current time
29+
currentTime := hc.Now()
30+
// Compare two timestamps if needed
31+
cmp := hlc.Compare(currentTime, req.Time)
32+
// ...
33+
```
1134

1235
### API
13-
*TODO*
36+
All clocks shares the same API:
37+
- `New() *SomeClock` creates a new clock object;
38+
- `clock.Now() SomeClock` returns a copy of the current state of the clock;
39+
- `clock.AddTicks(ticks int)` adds the specified number to the internal counter (thread-safe);
40+
- `clock.Tick(requestTime *SomeClock)` moves clock forward, comparing to the incoming value;
41+
- `Compare(a, b *SomeClock)` compares the current states of two clocks, returns -1, 0 or 1;
1442

1543
### References
16-
- [Lamport clock](https://lamport.azurewebsites.net/pubs/time-clocks.pdf)
17-
- [Vector clock](https://fileadmin.cs.lth.se/cs/Personal/Amr_Ergawy/dist-algos-papers/4.pdf)
18-
- [Hybrid logical clock](https://cse.buffalo.edu/tech-reports/2014-04.pdf)
19-
- [Martin Fowler blog](https://martinfowler.com/articles/patterns-of-distributed-systems/hybrid-clock.html)
44+
- [Martin Fowler's blog](https://martinfowler.com/articles/patterns-of-distributed-systems/)

hlc/hlc.go

+2
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ func (h *Hybrid) Tick(requestTime *Hybrid) {
8888
h.Ticks = latestTime.Ticks
8989
}
9090

91+
// NOTE: it was in an original paper, but times can go backwards
92+
// at this case comparing to the "original" timestamp
9193
func (h *Hybrid) GetCompactTimestampMs() int64 {
9294
h.mu.RLock()
9395
defer h.mu.RUnlock()

0 commit comments

Comments
 (0)