|
|
@@ -240,7 +240,12 @@ func (c *Conn) startup(cfg *ConnConfig) error {
|
|
|
m["COMPRESSION"] = c.compressor.Name()
|
|
|
}
|
|
|
|
|
|
- frame, err := c.exec(&writeStartupFrame{opts: m}, nil)
|
|
|
+ framer, err := c.exec(&writeStartupFrame{opts: m}, nil)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ frame, err := framer.parseFrame()
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
@@ -270,7 +275,12 @@ func (c *Conn) authenticateHandshake(authFrame *authenticateFrame) error {
|
|
|
req := &writeAuthResponseFrame{data: resp}
|
|
|
|
|
|
for {
|
|
|
- frame, err := c.exec(req, nil)
|
|
|
+ framer, err := c.exec(req, nil)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ frame, err := framer.parseFrame()
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
@@ -295,6 +305,8 @@ func (c *Conn) authenticateHandshake(authFrame *authenticateFrame) error {
|
|
|
default:
|
|
|
return fmt.Errorf("unknown frame response during authentication: %v", v)
|
|
|
}
|
|
|
+
|
|
|
+ framerPool.Put(framer)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -385,6 +397,7 @@ func (c *Conn) recv() error {
|
|
|
if err := framer.readFrame(&head); err != nil {
|
|
|
return err
|
|
|
}
|
|
|
+ defer framerPool.Put(framer)
|
|
|
|
|
|
frame, err := framer.parseFrame()
|
|
|
if err != nil {
|
|
|
@@ -435,7 +448,6 @@ type callReq struct {
|
|
|
|
|
|
func (c *Conn) releaseStream(stream int) {
|
|
|
call := &c.calls[stream]
|
|
|
- framerPool.Put(call.framer)
|
|
|
call.framer = nil
|
|
|
|
|
|
select {
|
|
|
@@ -450,7 +462,7 @@ func (c *Conn) handleTimeout() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func (c *Conn) exec(req frameWriter, tracer Tracer) (frame, error) {
|
|
|
+func (c *Conn) exec(req frameWriter, tracer Tracer) (*framer, error) {
|
|
|
// TODO: move tracer onto conn
|
|
|
var stream int
|
|
|
select {
|
|
|
@@ -512,19 +524,10 @@ func (c *Conn) exec(req frameWriter, tracer Tracer) (frame, error) {
|
|
|
return nil, NewErrProtocol("unexpected protocol version in response: got %d expected %d", v, c.version)
|
|
|
}
|
|
|
|
|
|
- frame, err := framer.parseFrame()
|
|
|
- if err != nil {
|
|
|
- return nil, err
|
|
|
- }
|
|
|
-
|
|
|
- if len(framer.traceID) > 0 {
|
|
|
- tracer.Trace(framer.traceID)
|
|
|
- }
|
|
|
-
|
|
|
- return frame, nil
|
|
|
+ return framer, nil
|
|
|
}
|
|
|
|
|
|
-func (c *Conn) prepareStatement(stmt string, trace Tracer) (*resultPreparedFrame, error) {
|
|
|
+func (c *Conn) prepareStatement(stmt string, tracer Tracer) (*QueryInfo, error) {
|
|
|
stmtsLRU.Lock()
|
|
|
if stmtsLRU.lru == nil {
|
|
|
initStmtsLRU(defaultMaxPreparedStmts)
|
|
|
@@ -536,7 +539,7 @@ func (c *Conn) prepareStatement(stmt string, trace Tracer) (*resultPreparedFrame
|
|
|
stmtsLRU.Unlock()
|
|
|
flight := val.(*inflightPrepare)
|
|
|
flight.wg.Wait()
|
|
|
- return flight.info, flight.err
|
|
|
+ return &flight.info, flight.err
|
|
|
}
|
|
|
|
|
|
flight := new(inflightPrepare)
|
|
|
@@ -548,16 +551,36 @@ func (c *Conn) prepareStatement(stmt string, trace Tracer) (*resultPreparedFrame
|
|
|
statement: stmt,
|
|
|
}
|
|
|
|
|
|
- resp, err := c.exec(prep, trace)
|
|
|
+ framer, err := c.exec(prep, tracer)
|
|
|
if err != nil {
|
|
|
flight.err = err
|
|
|
flight.wg.Done()
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
- switch x := resp.(type) {
|
|
|
+ frame, err := framer.parseFrame()
|
|
|
+ if err != nil {
|
|
|
+ flight.err = err
|
|
|
+ flight.wg.Done()
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ // TODO(zariel): tidy this up, simplify handling of frame parsing so its not duplicated
|
|
|
+ // everytime we need to parse a frame.
|
|
|
+ if len(framer.traceID) > 0 {
|
|
|
+ tracer.Trace(framer.traceID)
|
|
|
+ }
|
|
|
+
|
|
|
+ switch x := frame.(type) {
|
|
|
case *resultPreparedFrame:
|
|
|
- flight.info = x
|
|
|
+ // defensivly copy as we will recycle the underlying buffer after we
|
|
|
+ // return.
|
|
|
+ flight.info.Id = copyBytes(x.preparedID)
|
|
|
+ // the type info's should _not_ have a reference to the framers read buffer,
|
|
|
+ // therefore we can just copy them directly.
|
|
|
+ flight.info.Args = x.reqMeta.columns
|
|
|
+ flight.info.PKeyColumns = x.reqMeta.pkeyColumns
|
|
|
+ flight.info.Rval = x.respMeta.columns
|
|
|
case error:
|
|
|
flight.err = x
|
|
|
default:
|
|
|
@@ -571,7 +594,9 @@ func (c *Conn) prepareStatement(stmt string, trace Tracer) (*resultPreparedFrame
|
|
|
stmtsLRU.Unlock()
|
|
|
}
|
|
|
|
|
|
- return flight.info, flight.err
|
|
|
+ framerPool.Put(framer)
|
|
|
+
|
|
|
+ return &flight.info, flight.err
|
|
|
}
|
|
|
|
|
|
func (c *Conn) executeQuery(qry *Query) *Iter {
|
|
|
@@ -603,24 +628,19 @@ func (c *Conn) executeQuery(qry *Query) *Iter {
|
|
|
if qry.binding == nil {
|
|
|
values = qry.values
|
|
|
} else {
|
|
|
- binding := &QueryInfo{
|
|
|
- Id: info.preparedID,
|
|
|
- Args: info.reqMeta.columns,
|
|
|
- Rval: info.respMeta.columns,
|
|
|
- }
|
|
|
-
|
|
|
- values, err = qry.binding(binding)
|
|
|
+ values, err = qry.binding(info)
|
|
|
if err != nil {
|
|
|
return &Iter{err: err}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if len(values) != len(info.reqMeta.columns) {
|
|
|
+ if len(values) != len(info.Args) {
|
|
|
return &Iter{err: ErrQueryArgLength}
|
|
|
}
|
|
|
+
|
|
|
params.values = make([]queryValues, len(values))
|
|
|
for i := 0; i < len(values); i++ {
|
|
|
- val, err := Marshal(info.reqMeta.columns[i].TypeInfo, values[i])
|
|
|
+ val, err := Marshal(info.Args[i].TypeInfo, values[i])
|
|
|
if err != nil {
|
|
|
return &Iter{err: err}
|
|
|
}
|
|
|
@@ -631,7 +651,7 @@ func (c *Conn) executeQuery(qry *Query) *Iter {
|
|
|
}
|
|
|
|
|
|
frame = &writeExecuteFrame{
|
|
|
- preparedID: info.preparedID,
|
|
|
+ preparedID: info.Id,
|
|
|
params: params,
|
|
|
}
|
|
|
} else {
|
|
|
@@ -641,18 +661,28 @@ func (c *Conn) executeQuery(qry *Query) *Iter {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- resp, err := c.exec(frame, qry.trace)
|
|
|
+ framer, err := c.exec(frame, qry.trace)
|
|
|
if err != nil {
|
|
|
return &Iter{err: err}
|
|
|
}
|
|
|
|
|
|
+ resp, err := framer.parseFrame()
|
|
|
+ if err != nil {
|
|
|
+ return &Iter{err: err}
|
|
|
+ }
|
|
|
+
|
|
|
+ if len(framer.traceID) > 0 {
|
|
|
+ qry.trace.Trace(framer.traceID)
|
|
|
+ }
|
|
|
+
|
|
|
switch x := resp.(type) {
|
|
|
case *resultVoidFrame:
|
|
|
- return &Iter{}
|
|
|
+ return &Iter{framer: framer}
|
|
|
case *resultRowsFrame:
|
|
|
iter := &Iter{
|
|
|
- meta: x.meta,
|
|
|
- rows: x.rows,
|
|
|
+ meta: x.meta,
|
|
|
+ rows: x.rows,
|
|
|
+ framer: framer,
|
|
|
}
|
|
|
|
|
|
if len(x.meta.pagingState) > 0 && !qry.disableAutoPage {
|
|
|
@@ -669,7 +699,7 @@ func (c *Conn) executeQuery(qry *Query) *Iter {
|
|
|
|
|
|
return iter
|
|
|
case *resultKeyspaceFrame, *resultSchemaChangeFrame, *schemaChangeKeyspace, *schemaChangeTable:
|
|
|
- return &Iter{}
|
|
|
+ return &Iter{framer: framer}
|
|
|
case *RequestErrUnprepared:
|
|
|
stmtsLRU.Lock()
|
|
|
stmtCacheKey := c.addr + c.currentKeyspace + qry.stmt
|
|
|
@@ -679,11 +709,14 @@ func (c *Conn) executeQuery(qry *Query) *Iter {
|
|
|
return c.executeQuery(qry)
|
|
|
}
|
|
|
stmtsLRU.Unlock()
|
|
|
- return &Iter{err: x}
|
|
|
+ return &Iter{err: x, framer: framer}
|
|
|
case error:
|
|
|
- return &Iter{err: x}
|
|
|
+ return &Iter{err: x, framer: framer}
|
|
|
default:
|
|
|
- return &Iter{err: NewErrProtocol("Unknown type in response to execute query (%T): %s", x, x)}
|
|
|
+ return &Iter{
|
|
|
+ err: NewErrProtocol("Unknown type in response to execute query (%T): %s", x, x),
|
|
|
+ framer: framer,
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -710,7 +743,12 @@ func (c *Conn) UseKeyspace(keyspace string) error {
|
|
|
q := &writeQueryFrame{statement: `USE "` + keyspace + `"`}
|
|
|
q.params.consistency = Any
|
|
|
|
|
|
- resp, err := c.exec(q, nil)
|
|
|
+ framer, err := c.exec(q, nil)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ resp, err := framer.parseFrame()
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
@@ -757,28 +795,23 @@ func (c *Conn) executeBatch(batch *Batch) (*Iter, error) {
|
|
|
if entry.binding == nil {
|
|
|
args = entry.Args
|
|
|
} else {
|
|
|
- binding := &QueryInfo{
|
|
|
- Id: info.preparedID,
|
|
|
- Args: info.reqMeta.columns,
|
|
|
- Rval: info.respMeta.columns,
|
|
|
- }
|
|
|
- args, err = entry.binding(binding)
|
|
|
+ args, err = entry.binding(info)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if len(args) != len(info.reqMeta.columns) {
|
|
|
+ if len(args) != len(info.Args) {
|
|
|
return nil, ErrQueryArgLength
|
|
|
}
|
|
|
|
|
|
- b.preparedID = info.preparedID
|
|
|
- stmts[string(info.preparedID)] = entry.Stmt
|
|
|
+ b.preparedID = info.Id
|
|
|
+ stmts[string(info.Id)] = entry.Stmt
|
|
|
|
|
|
- b.values = make([]queryValues, len(info.reqMeta.columns))
|
|
|
+ b.values = make([]queryValues, len(info.Args))
|
|
|
|
|
|
- for j := 0; j < len(info.reqMeta.columns); j++ {
|
|
|
- val, err := Marshal(info.reqMeta.columns[j].TypeInfo, args[j])
|
|
|
+ for j := 0; j < len(info.Args); j++ {
|
|
|
+ val, err := Marshal(info.Args[j].TypeInfo, args[j])
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
@@ -792,13 +825,19 @@ func (c *Conn) executeBatch(batch *Batch) (*Iter, error) {
|
|
|
}
|
|
|
|
|
|
// TODO: should batch support tracing?
|
|
|
- resp, err := c.exec(req, nil)
|
|
|
+ framer, err := c.exec(req, nil)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ resp, err := framer.parseFrame()
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
switch x := resp.(type) {
|
|
|
case *resultVoidFrame:
|
|
|
+ framerPool.Put(framer)
|
|
|
return nil, nil
|
|
|
case *RequestErrUnprepared:
|
|
|
stmt, found := stmts[string(x.StatementId)]
|
|
|
@@ -807,6 +846,9 @@ func (c *Conn) executeBatch(batch *Batch) (*Iter, error) {
|
|
|
stmtsLRU.lru.Remove(c.addr + c.currentKeyspace + stmt)
|
|
|
stmtsLRU.Unlock()
|
|
|
}
|
|
|
+
|
|
|
+ framerPool.Put(framer)
|
|
|
+
|
|
|
if found {
|
|
|
return c.executeBatch(batch)
|
|
|
} else {
|
|
|
@@ -814,14 +856,17 @@ func (c *Conn) executeBatch(batch *Batch) (*Iter, error) {
|
|
|
}
|
|
|
case *resultRowsFrame:
|
|
|
iter := &Iter{
|
|
|
- meta: x.meta,
|
|
|
- rows: x.rows,
|
|
|
+ meta: x.meta,
|
|
|
+ rows: x.rows,
|
|
|
+ framer: framer,
|
|
|
}
|
|
|
|
|
|
return iter, nil
|
|
|
case error:
|
|
|
+ framerPool.Put(framer)
|
|
|
return nil, x
|
|
|
default:
|
|
|
+ framerPool.Put(framer)
|
|
|
return nil, NewErrProtocol("Unknown type in response to batch statement: %s", x)
|
|
|
}
|
|
|
}
|
|
|
@@ -900,7 +945,7 @@ func (c *Conn) awaitSchemaAgreement() (err error) {
|
|
|
}
|
|
|
|
|
|
type inflightPrepare struct {
|
|
|
- info *resultPreparedFrame
|
|
|
+ info QueryInfo
|
|
|
err error
|
|
|
wg sync.WaitGroup
|
|
|
}
|