mirror of
https://bitbucket.org/s_l_teichmann/mtsatellite
synced 2024-11-16 15:20:20 +01:00
mtredisalize: Add infrastructure to send backend store changes to separate daemons.
This commit is contained in:
parent
ef541f18f6
commit
400a65f563
33
cmd/mtredisalize/changetracker.go
Normal file
33
cmd/mtredisalize/changetracker.go
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"bitbucket.org/s_l_teichmann/mtredisalize/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChangeTracker struct {
|
||||||
|
mutex sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewChangeTracker() *ChangeTracker {
|
||||||
|
return &ChangeTracker{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct *ChangeTracker) BlockChanged(key []byte) {
|
||||||
|
ct.mutex.Lock()
|
||||||
|
defer ct.mutex.Unlock()
|
||||||
|
var err error
|
||||||
|
var coord common.Coord
|
||||||
|
if coord, err = common.DecodeStringBytesToCoord(key); err != nil {
|
||||||
|
log.Printf("decoding key failed: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("changed block: %v", coord)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct *ChangeTracker) FlushChanges(url string) (err error) {
|
||||||
|
log.Println("change flush triggered")
|
||||||
|
return
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ type LevelDBBackend struct {
|
||||||
interleaved bool
|
interleaved bool
|
||||||
encoder common.KeyTranscoder
|
encoder common.KeyTranscoder
|
||||||
decoder common.KeyTranscoder
|
decoder common.KeyTranscoder
|
||||||
|
changeTracker *ChangeTracker
|
||||||
mutex sync.RWMutex
|
mutex sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +30,7 @@ type LevelDBSession struct {
|
||||||
|
|
||||||
func NewLeveDBBackend(
|
func NewLeveDBBackend(
|
||||||
path string,
|
path string,
|
||||||
|
changeTracker *ChangeTracker,
|
||||||
interleaved bool,
|
interleaved bool,
|
||||||
cacheSize int) (ldb *LevelDBBackend, err error) {
|
cacheSize int) (ldb *LevelDBBackend, err error) {
|
||||||
|
|
||||||
|
@ -67,7 +69,8 @@ func NewLeveDBBackend(
|
||||||
db: db,
|
db: db,
|
||||||
interleaved: interleaved,
|
interleaved: interleaved,
|
||||||
encoder: encoder,
|
encoder: encoder,
|
||||||
decoder: decoder}
|
decoder: decoder,
|
||||||
|
changeTracker: changeTracker}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,6 +138,7 @@ func keyExists(db *leveldb.DB, key []byte) (exists bool, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ldbs *LevelDBSession) Store(hash, key, value []byte) (exists bool, err error) {
|
func (ldbs *LevelDBSession) Store(hash, key, value []byte) (exists bool, err error) {
|
||||||
|
origKey := key
|
||||||
if key, err = ldbs.backend.decoder(key); err != nil {
|
if key, err = ldbs.backend.decoder(key); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -150,6 +154,11 @@ func (ldbs *LevelDBSession) Store(hash, key, value []byte) (exists bool, err err
|
||||||
err = db.Put(wo, key, value)
|
err = db.Put(wo, key, value)
|
||||||
wo.Close()
|
wo.Close()
|
||||||
})
|
})
|
||||||
|
// This technically too early because this done in transactions
|
||||||
|
// which are commited (and possible fail) later.
|
||||||
|
if ldbs.backend.changeTracker != nil {
|
||||||
|
ldbs.backend.changeTracker.BlockChanged(origKey)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
const (
|
const (
|
||||||
Version = "0.3"
|
Version = "0.3"
|
||||||
GCDuration = "24h"
|
GCDuration = "24h"
|
||||||
|
ChangeDuration = "30s"
|
||||||
)
|
)
|
||||||
|
|
||||||
func usage() {
|
func usage() {
|
||||||
|
@ -36,7 +37,9 @@ func main() {
|
||||||
cacheSize int
|
cacheSize int
|
||||||
version bool
|
version bool
|
||||||
interleaved bool
|
interleaved bool
|
||||||
|
changeUrl string
|
||||||
gcDuration string
|
gcDuration string
|
||||||
|
changeDuration string
|
||||||
)
|
)
|
||||||
|
|
||||||
flag.Usage = usage
|
flag.Usage = usage
|
||||||
|
@ -46,8 +49,13 @@ func main() {
|
||||||
flag.StringVar(&host, "host", "", "host to bind")
|
flag.StringVar(&host, "host", "", "host to bind")
|
||||||
flag.IntVar(&cacheSize, "cache", 32, "cache size in MB")
|
flag.IntVar(&cacheSize, "cache", 32, "cache size in MB")
|
||||||
flag.BoolVar(&version, "version", false, "Print version and exit.")
|
flag.BoolVar(&version, "version", false, "Print version and exit.")
|
||||||
flag.BoolVar(&interleaved, "interleaved", false, "Backend stores key in interleaved form.")
|
flag.BoolVar(&interleaved,
|
||||||
flag.StringVar(&gcDuration, "gc-duration", GCDuration, "Duration between forced GCs.")
|
"interleaved", false, "Backend stores key in interleaved form.")
|
||||||
|
flag.StringVar(&gcDuration,
|
||||||
|
"gc-duration", GCDuration, "Duration between forced GCs.")
|
||||||
|
flag.StringVar(&changeDuration,
|
||||||
|
"change-duration", ChangeDuration, "Duration to aggregate changes.")
|
||||||
|
flag.StringVar(&changeUrl, "change-url", "", "URL to send changes to.")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if version {
|
if version {
|
||||||
|
@ -63,23 +71,44 @@ func main() {
|
||||||
err error
|
err error
|
||||||
backend Backend
|
backend Backend
|
||||||
gcDur time.Duration
|
gcDur time.Duration
|
||||||
|
chDur time.Duration
|
||||||
|
changeTracker *ChangeTracker
|
||||||
)
|
)
|
||||||
|
|
||||||
if gcDur, err = time.ParseDuration(gcDuration); err != nil {
|
if gcDur, err = time.ParseDuration(gcDuration); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setup the change listening stuff.
|
||||||
|
|
||||||
|
var changeChan <-chan time.Time
|
||||||
|
|
||||||
|
useChangeNotification := changeUrl != ""
|
||||||
|
|
||||||
|
if useChangeNotification {
|
||||||
|
if chDur, err = time.ParseDuration(changeDuration); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
changeChan = time.Tick(chDur)
|
||||||
|
changeTracker = NewChangeTracker()
|
||||||
|
} else {
|
||||||
|
// We will never receive ticks on this.
|
||||||
|
changeChan = make(<-chan time.Time)
|
||||||
|
}
|
||||||
|
|
||||||
path := flag.Arg(0)
|
path := flag.Arg(0)
|
||||||
|
|
||||||
if driver == "sqlite" {
|
if driver == "sqlite" {
|
||||||
if backend, err = NewSqliteBackend(path, interleaved); err != nil {
|
if backend, err = NewSqliteBackend(path, changeTracker, interleaved); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if backend, err = NewLeveDBBackend(path, interleaved, cacheSize); err != nil {
|
if backend, err = NewLeveDBBackend(
|
||||||
|
path, changeTracker, interleaved, cacheSize); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defer backend.Shutdown()
|
defer backend.Shutdown()
|
||||||
|
|
||||||
var listener net.Listener
|
var listener net.Listener
|
||||||
|
@ -127,6 +156,10 @@ func main() {
|
||||||
log.Println("Starting garbage collection.")
|
log.Println("Starting garbage collection.")
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
log.Println("Garbage collection done.")
|
log.Println("Garbage collection done.")
|
||||||
|
case <-changeChan:
|
||||||
|
if changeTracker != nil {
|
||||||
|
changeTracker.FlushChanges(changeUrl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ type SqliteBackend struct {
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
encoder common.KeyEncoder
|
encoder common.KeyEncoder
|
||||||
decoder common.KeyDecoder
|
decoder common.KeyDecoder
|
||||||
|
changeTracker *ChangeTracker
|
||||||
interleaved bool
|
interleaved bool
|
||||||
existsStmt *sql.Stmt
|
existsStmt *sql.Stmt
|
||||||
fetchStmt *sql.Stmt
|
fetchStmt *sql.Stmt
|
||||||
|
@ -58,9 +59,11 @@ func (ss *SqliteSession) Close() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSqliteBackend(path string, interleaved bool) (sqlb *SqliteBackend, err error) {
|
func NewSqliteBackend(
|
||||||
|
path string,
|
||||||
|
changeTracker *ChangeTracker, interleaved bool) (sqlb *SqliteBackend, err error) {
|
||||||
|
|
||||||
res := SqliteBackend{interleaved: interleaved}
|
res := SqliteBackend{interleaved: interleaved, changeTracker: changeTracker}
|
||||||
|
|
||||||
if res.db, err = sql.Open("sqlite3", path); err != nil {
|
if res.db, err = sql.Open("sqlite3", path); err != nil {
|
||||||
return
|
return
|
||||||
|
@ -207,6 +210,11 @@ func (ss *SqliteSession) Store(hash, key, value []byte) (exists bool, err error)
|
||||||
insertStmt := ss.txStmt(ss.backend.insertStmt)
|
insertStmt := ss.txStmt(ss.backend.insertStmt)
|
||||||
_, err = insertStmt.Exec(pos, value)
|
_, err = insertStmt.Exec(pos, value)
|
||||||
}
|
}
|
||||||
|
// This technically too early because this done in transactions
|
||||||
|
// which are commited (and possible fail) later.
|
||||||
|
if ss.backend.changeTracker != nil {
|
||||||
|
ss.backend.changeTracker.BlockChanged(key)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -216,6 +216,15 @@ func DecodeStringFromBytesToInterleaved(key []byte) (v int64, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DecodeStringBytesToCoord(key []byte) (coord Coord, err error) {
|
||||||
|
var k int64
|
||||||
|
if k, err = DecodeStringFromBytes(key); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
coord = PlainToCoord(k)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func EncodeStringToBytesFromInterleaved(key int64) ([]byte, error) {
|
func EncodeStringToBytesFromInterleaved(key int64) ([]byte, error) {
|
||||||
return EncodeStringToBytes(TransformInterleavedToPlain(key))
|
return EncodeStringToBytes(TransformInterleavedToPlain(key))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user