7
7
local json = require (' json' )
8
8
local avro_schema = require (' avro_schema' )
9
9
local utils = require (' graphql.utils' )
10
+ local clock = require (' clock' )
10
11
11
12
local accessor_general = {}
12
13
local DEF_RESULTING_OBJECT_CNT_MAX = 10000
13
14
local DEF_FETCHED_OBJECT_CNT_MAX = 10000
15
+ local DEF_TIMEOUT_MS = 1000
14
16
15
17
--- Validate and compile set of avro schemas (with respect to service fields).
16
18
--- @tparam table schemas map where keys are string names and values are
553
555
--- * `count` (number),
554
556
--- * `objs` (table, list of objects),
555
557
--- * `pivot_found` (boolean),
556
- --- * `statistics ` (table, per-query statistics ).
558
+ --- * `qcontext ` (table, per-query local storage ).
557
559
---
558
560
--- @tparam cdata tuple flatten representation of an object to process
559
561
---
@@ -578,14 +580,17 @@ local function process_tuple(state, tuple, opts)
578
580
local filter = opts .filter
579
581
local do_filter = opts .do_filter
580
582
local pivot_filter = opts .pivot_filter
581
- local qstats = state .statistics
583
+ local qcontext = state .qcontext
584
+ local qstats = qcontext .statistics
582
585
local resulting_object_cnt_max = opts .resulting_object_cnt_max
583
586
local fetched_object_cnt_max = opts .fetched_object_cnt_max
584
587
qstats .fetched_object_cnt = qstats .fetched_object_cnt + 1
585
588
assert (qstats .fetched_object_cnt <= fetched_object_cnt_max ,
586
589
(' fetched object count[%d] exceeds limit[%d] ' ..
587
590
' (`fetched_object_cnt_max` in accessor)' ):format (
588
591
qstats .fetched_object_cnt , fetched_object_cnt_max ))
592
+ assert (qcontext .deadline_clock > clock .monotonic64 (),
593
+ ' query execution timeout exceeded, use `timeout_ms` to increase it' )
589
594
590
595
-- convert tuple -> object
591
596
local obj = opts .unflatten_tuple (opts .collection_name , tuple ,
@@ -706,7 +711,7 @@ local function select_internal(self, collection_name, from, filter, args, extra)
706
711
count = 0 ,
707
712
objs = {},
708
713
pivot_found = false ,
709
- statistics = extra .qcontext . statistics
714
+ qcontext = extra .qcontext
710
715
}
711
716
712
717
-- read only process_tuple options
@@ -804,6 +809,22 @@ local function validate_funcs(funcs)
804
809
type (funcs .unflatten_tuple ))
805
810
end
806
811
812
+ --- This function is called on first select related to a query. Its purpose is
813
+ --- to initialize qcontext table.
814
+ --- @tparam table accessor
815
+ --- @tparam table qcontext per-query table which stores query internal state;
816
+ --- all neccessary initialization of this parameter should be performed by this
817
+ -- function
818
+ local function init_qcontext (accessor , qcontext )
819
+ local settings = accessor .settings
820
+ qcontext .statistics = {
821
+ resulting_object_cnt = 0 ,
822
+ fetched_object_cnt = 0
823
+ }
824
+ qcontext .deadline_clock = clock .monotonic64 () +
825
+ settings .timeout_ms * 1000 * 1000
826
+ end
827
+
807
828
--- Create a new data accessor.
808
829
---
809
830
--- Provided `funcs` argument determines certain functions for retrieving
814
835
--- shown below; additional attributes `resulting_object_cnt_max` and
815
836
--- `fetched_object_cnt_max` are optional positive numbers which help to control
816
837
--- query behaviour in case it requires more resources than expected _(default
817
- --- value is 10,000)_
838
+ --- value is 10,000)_; `timeout_ms` _(default is 1000)_
818
839
---
819
840
--- @tparam table funcs set of functions (`is_collection_exists`, `get_index`,
820
841
--- `get_primary_index`, `unflatten_tuple`) allows this abstract data accessor
@@ -864,6 +885,8 @@ function accessor_general.new(opts, funcs)
864
885
DEF_RESULTING_OBJECT_CNT_MAX
865
886
local fetched_object_cnt_max = opts .fetched_object_cnt_max or
866
887
DEF_FETCHED_OBJECT_CNT_MAX
888
+ -- todo: move this setting to `tgql.compile` after #59
889
+ local timeout_ms = opts .timeout_ms or DEF_TIMEOUT_MS
867
890
868
891
assert (type (schemas ) == ' table' ,
869
892
' schemas must be a table, got ' .. type (schemas ))
@@ -910,7 +933,8 @@ function accessor_general.new(opts, funcs)
910
933
funcs = funcs ,
911
934
settings = {
912
935
resulting_object_cnt_max = resulting_object_cnt_max ,
913
- fetched_object_cnt_max = fetched_object_cnt_max
936
+ fetched_object_cnt_max = fetched_object_cnt_max ,
937
+ timeout_ms = timeout_ms
914
938
}
915
939
}, {
916
940
__index = {
@@ -928,11 +952,11 @@ function accessor_general.new(opts, funcs)
928
952
' from must be nil or from.connection_name ' ..
929
953
' must be a string, got ' ..
930
954
type ((from or {}).connection_name ))
931
- -- use `extra. qcontext` to store per-query variables
932
- extra .qcontext .statistics = extra . qcontext . statistics or {
933
- resulting_object_cnt = 0 ,
934
- fetched_object_cnt = 0
935
- }
955
+ -- ` qcontext` initialization
956
+ if extra .qcontext .initialized ~= true then
957
+ init_qcontext ( self , extra . qcontext )
958
+ extra . qcontext . initialized = true
959
+ end
936
960
return select_internal (self , collection_name , from , filter ,
937
961
args , extra )
938
962
end ,
0 commit comments