Commit 134eeba1 authored by Geoff Simmons's avatar Geoff Simmons

NextTxGroup() supports queries (this gets queries into the public API).

parent 8f45f964
......@@ -103,6 +103,7 @@ type grpNode struct {
// function.
type Query struct {
cursor *Cursor
expr *qExpr
incomplete map[uint32]Tx
ignoreSess map[uint32]existence
grpNodes map[uint32]grpNode
......@@ -126,19 +127,35 @@ func (c *Cursor) rawTxGrp() []Tx {
// how transactions from the log should be aggregated: VXID, Request, Session
// or Raw grouping.
//
// XXX: VSL queries not yet implemented
// If the query argument is non-empty, it is interpreted as a query
// string for filtering log transactions. See vsl-query(7) for details
// of the query language and its semantics. When a query is in effect,
// only transaction groups that match the query are returned by
// NextTxGroup().
//
// Queries currently do not support singly-quoted strings (only double
// quotes).
func (c *Cursor) NewQuery(grp Grouping, query string) (*Query, error) {
var expr *qExpr
if c == nil || c.cursor == nil {
return nil, errors.New("Cursor is nil or uninitialized")
}
if err := c.log.checkNil(); err != nil {
return nil, err
}
if query != "" {
qexpr, err := parseQuery(query)
if err != nil {
return nil, err
}
expr = qexpr
}
txMap := make(map[uint32]Tx)
sessSet := make(map[uint32]existence)
grpNodes := make(map[uint32]grpNode)
return &Query{
cursor: c,
expr: expr,
grp: grp,
incomplete: txMap,
ignoreSess: sessSet,
......@@ -279,12 +296,18 @@ func (q *Query) doEnd(rec Record) []Tx {
if q.grp == VXID {
txGrp := []Tx{tx}
delete(q.incomplete, vxid32)
if q.expr != nil && !q.expr.eval(txGrp) {
return nil
}
return txGrp
}
node, exists := q.grpNodes[vxid32]
if !exists {
txGrp := []Tx{tx}
if q.expr != nil && !q.expr.eval(txGrp) {
return nil
}
return txGrp
}
q.incomplete[vxid32] = tx
......@@ -328,6 +351,9 @@ func (q *Query) doEnd(rec Record) []Tx {
}
nodeQ = nextQ
}
if q.expr != nil && !q.expr.eval(txGrp) {
return nil
}
return txGrp
}
......@@ -342,7 +368,8 @@ func (q *Query) doRec(rec Record) {
// NextTxGroup returns the next group of transactions from the
// log. Transactions are aggregated according to the Grouping argument
// given in NewQuery().
// given in NewQuery(), and filtered according to the query
// expression.
//
// The Status return value indicates whether there was an error
// reading the log, whether there was an end condition (EOL or EOF),
......
......@@ -372,3 +372,46 @@ func TestNextTxGroupSessionAll(t *testing.T) {
}
checkTxGroups(t, txGrps, expSessLog)
}
// Test vectors in query_eval_test.go (mostly adapted from l00001.vtc)
func TestNextTxGroupQuery(t *testing.T) {
l := New()
defer l.Release()
vec := queryRecTestVec
vec = append(vec, queryTxTestVec...)
vec = append(vec, queryVxidTestVec...)
for _, v := range vec {
if v.fail == "fail" {
continue
}
t.Run(v.name, func(t *testing.T) {
c, err := l.NewCursorFile(l1Log)
if err != nil {
t.Fatal("NewCursorFile(l00001.log):", err)
return
}
defer c.Delete()
q, err := c.NewQuery(VXID, v.query)
if err != nil {
t.Fatal("NewQuery(VXID):", err)
return
}
txGrp, status := q.NextTxGroup()
if status != More {
t.Fatalf("NextTxGroup() status want=More got=%v",
status)
return
}
if len(txGrp) != 1 {
t.Errorf("len(txGrp) want=1 got=%v", len(txGrp))
if len(txGrp) == 0 {
return
}
}
if txGrp[0].VXID != 118200424 {
t.Errorf("tx.VXID want=118200424 got=%v",
txGrp[0].VXID)
}
})
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment