1
0
Fork 0
You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

116 lines
2.0 KiB
Go

package queue
import (
"time"
"github.com/rqlite/rqlite/command"
)
type Execer interface {
Execute(er *command.ExecuteRequest) ([]*command.ExecuteResult, error)
}
type Queue struct {
maxSize int
batchSize int
timeout time.Duration
store Execer
c chan *command.Statement
done chan struct{}
closed chan struct{}
flush chan struct{}
}
func New(maxSize, batchSize int, t time.Duration, e Execer) *Queue {
q := &Queue{
maxSize: maxSize,
batchSize: batchSize,
timeout: t,
store: e,
c: make(chan *command.Statement, maxSize),
done: make(chan struct{}),
closed: make(chan struct{}),
flush: make(chan struct{}),
}
go q.run()
return q
}
// Requests or ExecuteRequests? Gotta be requests, and merge inside single ER. Maybe just
// needs to be Statements
func (q *Queue) Write(stmt *command.Statement) error {
if stmt == nil {
return nil
}
q.c <- stmt
return nil
}
func (q *Queue) Flush() error {
q.flush <- struct{}{}
return nil
}
func (q *Queue) Close() error {
close(q.done)
<-q.closed
return nil
}
func (q *Queue) Depth() int {
return len(q.c)
}
func (q *Queue) run() {
defer close(q.closed)
var stmts []*command.Statement
timer := time.NewTimer(q.timeout)
timer.Stop()
writeFn := func(stmts []*command.Statement) {
q.exec(stmts)
stmts = nil
timer.Stop()
}
for {
select {
case s := <-q.c:
stmts = append(stmts, s)
if len(stmts) == 1 {
timer.Reset(q.timeout)
}
if len(stmts) == q.batchSize {
writeFn(stmts)
}
case <-timer.C:
writeFn(stmts)
case <-q.flush:
writeFn(stmts)
case <-q.done:
timer.Stop()
return
}
}
}
func (q *Queue) exec(stmts []*command.Statement) error {
if stmts == nil || len(stmts) == 0 {
return nil
}
er := &command.ExecuteRequest{
Request: &command.Request{
Statements: stmts,
},
}
// Doesn't handle leader-redirect, transparent forwarding, etc.
// Would need a "wrapped" store which handles it.
_, err := q.store.Execute(er)
return err
}