@@ -2,7 +2,6 @@ package plugin
2
2
3
3
import (
4
4
"context"
5
- "errors"
6
5
"fmt"
7
6
"log"
8
7
"os"
@@ -21,7 +20,6 @@ import (
21
20
"github.com/hashicorp/go-hclog"
22
21
"github.com/turbot/go-kit/helpers"
23
22
connectionmanager "github.com/turbot/steampipe-plugin-sdk/v5/connection"
24
- "github.com/turbot/steampipe-plugin-sdk/v5/error_helpers"
25
23
"github.com/turbot/steampipe-plugin-sdk/v5/grpc"
26
24
"github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto"
27
25
"github.com/turbot/steampipe-plugin-sdk/v5/logging"
@@ -264,28 +262,24 @@ func (p *Plugin) ConnectionSchemaChanged(connection *Connection) error {
264
262
return nil
265
263
}
266
264
267
- func (p * Plugin ) executeForConnection (ctx context.Context , req * proto.ExecuteRequest , connectionName string , outputChan chan * proto.ExecuteResponse ) (err error ) {
265
+ func (p * Plugin ) executeForConnection (streamContext context.Context , req * proto.ExecuteRequest , connectionName string , outputChan chan * proto.ExecuteResponse , logger hclog. Logger ) (err error ) {
268
266
const rowBufferSize = 10
269
267
var rowChan = make (chan * proto.Row , rowBufferSize )
270
268
271
269
executeData := req .ExecuteConnectionData [connectionName ]
272
270
273
271
// build callId for this connection (this is necessary is the plugin Execute call may be for an aggregator connection)
274
272
connectionCallId := p .getConnectionCallId (req .CallId , connectionName )
275
- // when done, remove call id from map
276
- defer p .clearCallId (connectionCallId )
277
273
278
274
log .Printf ("[INFO] executeForConnection callId: %s, connectionCallId: %s, connection: %s table: %s cols: %s" , req .CallId , connectionCallId , connectionName , req .Table , strings .Join (req .QueryContext .Columns , "," ))
279
275
280
276
defer func () {
281
- log .Printf ("[TRACE] executeForConnection DEFER (%s) " , connectionCallId )
282
277
if r := recover (); r != nil {
283
- log .Printf ("[WARN] Execute recover from panic: callId: %s table: %s error: %v" , connectionCallId , req .Table , r )
278
+ log .Printf ("[WARN] executeForConnection recover from panic: callId: %s table: %s error: %v" , connectionCallId , req .Table , r )
284
279
err = helpers .ToError (r )
285
280
return
286
281
}
287
-
288
- log .Printf ("[TRACE] Execute complete callId: %s table: %s " , connectionCallId , req .Table )
282
+ log .Printf ("[INFO] executeForConnection COMPLETE callId: %s, connectionCallId: %s, connection: %s table: %s cols: %s " , req .CallId , connectionCallId , connectionName , req .Table , strings .Join (req .QueryContext .Columns , "," ))
289
283
}()
290
284
291
285
// the connection property must be set already
@@ -312,6 +306,16 @@ func (p *Plugin) executeForConnection(ctx context.Context, req *proto.ExecuteReq
312
306
log .Printf ("[INFO] caching is disabled for table %s" , table .Name )
313
307
}
314
308
}
309
+
310
+ // if cache NOT disabled, create a fresh context for this scan
311
+ ctx := streamContext
312
+ var cancel context.CancelFunc
313
+ if cacheEnabled {
314
+ // get a fresh context which includes telemetry data and logger
315
+ ctx , cancel = context .WithCancel (context .Background ())
316
+ }
317
+ ctx = p .buildExecuteContext (ctx , req , logger )
318
+
315
319
logging .LogTime ("Start execute" )
316
320
317
321
queryContext := NewQueryContext (req .QueryContext , limitParam , cacheEnabled , cacheTTL , table )
@@ -336,6 +340,10 @@ func (p *Plugin) executeForConnection(ctx context.Context, req *proto.ExecuteReq
336
340
return err
337
341
}
338
342
343
+ // set the cancel func on the query data
344
+ // (this is only used if the cache is enabled - if a set request has no subscribers)
345
+ queryData .cancel = cancel
346
+
339
347
// get the matrix item
340
348
log .Printf ("[TRACE] GetMatrixItem" )
341
349
var matrixItem []map [string ]any
@@ -362,23 +370,25 @@ func (p *Plugin) executeForConnection(ctx context.Context, req *proto.ExecuteReq
362
370
ConnectionName : connectionName ,
363
371
TtlSeconds : queryContext .CacheTTL ,
364
372
CallId : connectionCallId ,
373
+ StreamContext : streamContext ,
365
374
}
366
375
// can we satisfy this request from the cache?
367
376
if cacheEnabled {
368
377
log .Printf ("[INFO] cacheEnabled, trying cache get (%s)" , connectionCallId )
369
378
370
379
// create a function to increment cachedRowsFetched and stream a row
371
- streamRowFunc := func (row * proto.Row ) {
380
+ streamUncachedRowFunc := queryData .streamRow
381
+ streamCachedRowFunc := func (row * proto.Row ) {
372
382
// if row is not nil (indicating completion), increment cachedRowsFetched
373
383
if row != nil {
374
384
atomic .AddInt64 (& queryData .queryStatus .cachedRowsFetched , 1 )
375
385
}
376
- queryData . streamRow (row )
386
+ streamUncachedRowFunc (row )
377
387
}
378
388
379
389
start := time .Now ()
380
390
// try to fetch this data from the query cache
381
- cacheErr := p .queryCache .Get (ctx , cacheRequest , streamRowFunc )
391
+ cacheErr := p .queryCache .Get (ctx , cacheRequest , streamUncachedRowFunc , streamCachedRowFunc )
382
392
if cacheErr == nil {
383
393
// so we got a cached result - stream it out
384
394
log .Printf ("[INFO] queryCacheGet returned CACHE HIT (%s)" , connectionCallId )
@@ -393,45 +403,40 @@ func (p *Plugin) executeForConnection(ctx context.Context, req *proto.ExecuteReq
393
403
}
394
404
395
405
// so the cache call failed, with either a cache-miss or other error
396
- if query_cache .IsCacheMiss (cacheErr ) {
397
- log .Printf ("[TRACE] cache MISS" )
398
- } else if errors .Is (cacheErr , error_helpers.QueryError {}) {
399
- // if this is a QueryError, this means the pending item we were waitign for failed
400
- // > we also fail
406
+ if ! query_cache .IsCacheMiss (cacheErr ) {
407
+ log .Printf ("[WARN] queryCacheGet returned err %s" , cacheErr .Error ())
401
408
return cacheErr
402
- } else {
403
- // otherwise just log the cache error
404
- log .Printf ("[TRACE] queryCacheGet returned err %s" , cacheErr .Error ())
405
409
}
406
-
410
+ // otherwise just log the cache miss error
407
411
log .Printf ("[INFO] queryCacheGet returned CACHE MISS (%s)" , connectionCallId )
408
412
} else {
409
- log .Printf ("[INFO] Cache DISABLED connectionCallId: %s " , connectionCallId )
413
+ log .Printf ("[INFO] Cache DISABLED (%s) " , connectionCallId )
410
414
}
411
415
416
+ // so we need to fetch the data
417
+
412
418
// asyncronously fetch items
413
- log .Printf ("[TRACE ] calling fetchItems, table: %s, matrixItem: %v, limit: %d, connectionCallId: %s \" " , table .Name , queryData .Matrix , limit , connectionCallId )
419
+ log .Printf ("[INFO ] calling fetchItems, table: %s, matrixItem: %v, limit: %d (%s) " , table .Name , queryData .Matrix , limit , connectionCallId )
414
420
if err := table .fetchItems (ctx , queryData ); err != nil {
415
421
log .Printf ("[WARN] fetchItems returned an error, table: %s, error: %v" , table .Name , err )
416
422
return err
417
423
418
424
}
419
- logging .LogTime ("Calling build Rows" )
420
-
421
- log .Printf ("[TRACE] buildRowsAsync connectionCallId: %s" , connectionCallId )
422
425
423
426
// asyncronously build rows
427
+ logging .LogTime ("Calling build Rows" )
428
+ log .Printf ("[TRACE] buildRowsAsync (%s)" , connectionCallId )
429
+
424
430
// channel used by streamRows when it receives an error to tell buildRowsAsync to stop
425
431
doneChan := make (chan bool )
426
432
queryData .buildRowsAsync (ctx , rowChan , doneChan )
427
433
428
- log .Printf ("[TRACE] streamRows connectionCallId: %s" , connectionCallId )
429
-
434
+ // stream rows either into cache (if enabled) or back across GRPC (if not)
430
435
logging .LogTime ("Calling streamRows" )
431
436
432
- // stream rows across GRPC
433
437
err = queryData .streamRows (ctx , rowChan , doneChan )
434
438
if err != nil {
439
+ log .Printf ("[WARN] queryData.streamRows returned error: %s" , err .Error ())
435
440
return err
436
441
}
437
442
@@ -569,42 +574,47 @@ func (p *Plugin) buildConnectionSchemaMap() map[string]*grpc.PluginSchema {
569
574
return res
570
575
}
571
576
572
- func (p * Plugin ) getConnectionCallId (callId string , connectionName string ) string {
573
- // add connection name onto call id
574
- connectionCallId := grpc .BuildConnectionCallId (callId , connectionName )
577
+ // ensure callId is unique fo rthis plugin instance - important as it is used to key set requests
578
+ func (p * Plugin ) getUniqueCallId (callId string ) string {
575
579
// store as orig as we may mutate connectionCallId to dedupe
576
- orig := connectionCallId
580
+ orig := callId
577
581
// check if it unique - this is crucial as it is used to key 'set requests` in the query cache
578
582
idx := 0
579
583
p .callIdLookupMut .RLock ()
580
584
for {
581
- if _ , callIdExists := p .callIdLookup [connectionCallId ]; ! callIdExists {
585
+ if _ , callIdExists := p .callIdLookup [callId ]; ! callIdExists {
582
586
// release read lock and get a write lock
583
587
p .callIdLookupMut .RUnlock ()
584
588
p .callIdLookupMut .Lock ()
585
589
586
590
// recheck as ther eis a race condition to acquire a write lockm
587
- if _ , callIdExists := p .callIdLookup [connectionCallId ]; ! callIdExists {
591
+ if _ , callIdExists := p .callIdLookup [callId ]; ! callIdExists {
588
592
// store in map
589
- p .callIdLookup [connectionCallId ] = struct {}{}
593
+ p .callIdLookup [callId ] = struct {}{}
590
594
p .callIdLookupMut .Unlock ()
591
- return connectionCallId
595
+ return callId
592
596
}
593
597
594
598
// someone must have got in there before us - downgrade lock again
595
599
p .callIdLookupMut .Unlock ()
596
600
p .callIdLookupMut .RLock ()
597
601
}
598
602
// so the id exists already - add a suffix
599
- log .Printf ("[WARN] getConnectionCallId duplicate call id %s - adding suffix" , connectionCallId )
600
- connectionCallId = fmt .Sprintf ("%s%d" , orig , idx )
603
+ log .Printf ("[WARN] getUniqueCallId duplicate call id %s - adding suffix" , callId )
604
+ callId = fmt .Sprintf ("%s%d" , orig , idx )
601
605
idx ++
602
606
603
607
}
604
608
p .callIdLookupMut .RUnlock ()
605
- return connectionCallId
609
+ return callId
610
+ }
611
+
612
+ func (p * Plugin ) getConnectionCallId (callId string , connectionName string ) string {
613
+ // add connection name onto call id
614
+ return grpc .BuildConnectionCallId (callId , connectionName )
606
615
}
607
616
617
+ // remove callId from callIdLookup
608
618
func (p * Plugin ) clearCallId (connectionCallId string ) {
609
619
p .callIdLookupMut .Lock ()
610
620
delete (p .callIdLookup , connectionCallId )
0 commit comments