2020-04-11 11:33:10 +03:00
|
|
|
package sync
|
2020-03-18 19:39:36 +03:00
|
|
|
|
|
|
|
import (
|
|
|
|
"time"
|
|
|
|
|
2020-08-19 17:47:17 +03:00
|
|
|
"github.com/unistack-org/micro/v3/store"
|
2020-03-18 19:39:36 +03:00
|
|
|
"github.com/pkg/errors"
|
|
|
|
)
|
|
|
|
|
|
|
|
type operation struct {
|
|
|
|
operation action
|
|
|
|
record *store.Record
|
|
|
|
deadline time.Time
|
|
|
|
retries int
|
|
|
|
maxiumum int
|
|
|
|
}
|
|
|
|
|
|
|
|
// action represents the type of a queued operation
|
|
|
|
type action int
|
|
|
|
|
|
|
|
const (
|
|
|
|
readOp action = iota + 1
|
|
|
|
writeOp
|
|
|
|
deleteOp
|
|
|
|
listOp
|
|
|
|
)
|
|
|
|
|
2020-04-11 11:33:10 +03:00
|
|
|
func (c *syncStore) syncManager() {
|
2020-03-18 19:39:36 +03:00
|
|
|
tickerAggregator := make(chan struct{ index int })
|
|
|
|
for i, ticker := range c.pendingWriteTickers {
|
|
|
|
go func(index int, c chan struct{ index int }, t *time.Ticker) {
|
|
|
|
for range t.C {
|
|
|
|
c <- struct{ index int }{index: index}
|
|
|
|
}
|
|
|
|
}(i, tickerAggregator, ticker)
|
|
|
|
}
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case i := <-tickerAggregator:
|
|
|
|
println(i.index, "ticked")
|
|
|
|
c.processQueue(i.index)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-11 11:33:10 +03:00
|
|
|
func (c *syncStore) processQueue(index int) {
|
2020-03-18 19:39:36 +03:00
|
|
|
c.Lock()
|
|
|
|
defer c.Unlock()
|
|
|
|
q := c.pendingWrites[index]
|
|
|
|
for i := 0; i < q.Len(); i++ {
|
|
|
|
r, ok := q.PopFront()
|
|
|
|
if !ok {
|
2020-04-11 11:33:10 +03:00
|
|
|
panic(errors.Errorf("retrieved an invalid value from the L%d sync queue", index+1))
|
2020-03-18 19:39:36 +03:00
|
|
|
}
|
|
|
|
ir, ok := r.(*internalRecord)
|
|
|
|
if !ok {
|
2020-04-11 11:33:10 +03:00
|
|
|
panic(errors.Errorf("retrieved a non-internal record from the L%d sync queue", index+1))
|
2020-03-18 19:39:36 +03:00
|
|
|
}
|
|
|
|
if !ir.expiresAt.IsZero() && time.Now().After(ir.expiresAt) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
nr := &store.Record{
|
|
|
|
Key: ir.key,
|
|
|
|
}
|
|
|
|
nr.Value = make([]byte, len(ir.value))
|
|
|
|
copy(nr.Value, ir.value)
|
|
|
|
if !ir.expiresAt.IsZero() {
|
|
|
|
nr.Expiry = time.Until(ir.expiresAt)
|
|
|
|
}
|
|
|
|
// Todo = internal queue also has to hold the corresponding store.WriteOptions
|
2020-04-11 11:33:10 +03:00
|
|
|
if err := c.syncOpts.Stores[index+1].Write(nr); err != nil {
|
2020-03-18 19:39:36 +03:00
|
|
|
// some error, so queue for retry and bail
|
|
|
|
q.PushBack(ir)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func intpow(x, y int64) int64 {
|
|
|
|
result := int64(1)
|
|
|
|
for 0 != y {
|
|
|
|
if 0 != (y & 1) {
|
|
|
|
result *= x
|
|
|
|
}
|
|
|
|
y >>= 1
|
|
|
|
x *= x
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|