QueryState¶
#include "ThriftHandler/QueryState.h"
QueryState is a set of C++ classes that:
Consolidates information about current and past SQL queries.
Record execution time of blocks of C++ code, and log with call stack relationships.
Classes¶
- QueryStates
Manages and aggregates
QueryStateobjects. E.g.DBHandlerhas oneQueryStatesmember variable.- QueryState
Manages the lifetime of a single query. Attributes/methods (e.g.
bool just_explain) may be moved/added directly to this class as needed to model the state of SQL queries. As such, the development of this class can be considered ongoing, as a reflection of the ongoing development of the OmniSciDB itself. Timing of code blocks (i.e. function calls) are stored in a list ofEvents.- Event
Records start and stop times for the lifetime of a corresponding
Timerobject.Events can have parent/child relationships to model call-stack nesting.- Timer
Events andTimers are created at the same time. ATimerobject is typically instantiated with a__func__parameter, which shows up in the logs along with the duration between its construction and destruction.- QueryStateProxy
A light-weight object that can both create and be created by
Timerobjects so that call-stack relationships between parent/childEvents are recorded.
Example Usage¶
In DBHandler::sql_execute():
// session_ptr and query_str are already set or passed into the function.
auto query_state = create_query_state(session_ptr, query_str); // Line A
auto stdlog = STDLOG(query_state); // Line B
...
foo(query_state->createQueryStateProxy()); // Line C
In foo(QueryStateProxy query_state_proxy):
auto timer = query_state_proxy.createTimer(__func__); // Line D
...
bar(timer.createQueryStateProxy()); // Line E
In bar(QueryStateProxy query_state_proxy):
auto timer = query_state_proxy.createTimer(__func__); // Line F
...
- Line A
auto query_state = create_query_state(session_ptr, query_str); // Line ACreate a new
QueryStatein theDBHandler::query_states_member variable for the current query.- Line B
auto stdlog = STDLOG(query_state); // Line BConnects the
QueryStateobject to thestdlogwhich will log theQueryStateinformation duringstdlog’s destructor.- Line C
foo(query_state->createQueryStateProxy()); // Line CTo pass
QueryStateto other functions, it is preferred to generate a light-weightQueryStateProxyobject rather than pass theQueryStatereference. This is becauseTimerobjects also generateQueryStateProxyobjects to pass to other functions in order to track nested timings. Thus to avoid having redundant versions of functions that accept bothQueryStateandQueryStateProxytypes, it is preferred for members/functions to acceptQueryStateProxy. The originalQueryStatereference is then available viaQueryStateProxy::getQueryState().- Line D
auto timer = query_state_proxy.createTimer(__func__); // Line DThe lifetime of
timeris recorded and stored in the originalquery_stateobject from Line A, and will appear in the logs associated with__func__ = "foo"in this case.- Line E
bar(timer.createQueryStateProxy()); // Line ESimilar to Line C, this is how to create nested timings when invoking another function deeper in the call stack.
- Line F
auto timer = query_state_proxy.createTimer(__func__); // Line FSimilar to Line D, the created
timerwill show up nested under the previousTimerobject.
The two timer instances above directly result in the nested log lines:
foo 140038217238272 - total time 578 ms
bar 140038217238272 - total time 578 ms
(The long integer is the thread id.) Though only a couple examples were given here, each Timer object can
spawn any number of QueryStateProxy instances, and vice-versa.
Summary¶
The above example demonstrates how to:
Create new
QueryStateobjects and connect them withSessionInfoandStdLoginstances.Create nested
Timerobjects usingQueryStateProxyobjects as intermediaries to model nested function calls.