QueryEngine.h 6.41 KB
Newer Older
Alessio Netti's avatar
Alessio Netti committed
1
2
3
4
5
6
7
//
// Created by Netti, Alessio on 10.12.18.
//

#ifndef PROJECT_QUERYENGINE_H
#define PROJECT_QUERYENGINE_H

8
9
#include "sensornavigator.h"
#include "sensorbase.h"
Alessio Netti's avatar
Alessio Netti committed
10
#include <atomic>
Alessio Netti's avatar
Alessio Netti committed
11
12
13
14

using namespace std;

//Typedef for the callback used to retrieve sensors
15
typedef vector<reading_t>* (*QueryEngineCallback)(const string&, const uint64_t, const uint64_t, vector<reading_t>*, const bool rel);
Alessio Netti's avatar
Alessio Netti committed
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

/**
 * Class that grants query access to local and remote sensors
 *
 * This class provides an abstraction layer to where the data analytics framework is executed: access interface to
 * sensor data is the same on dcdbpusher and collectagent.
 * This class is implemented according to the Singleton design pattern.
 */
class QueryEngine {

public:

    /**
    * @brief            Returns an instance to a QueryEngine object
    *
    *                   The QueryEngine class is implemented as a singleton: therefore, all entities calling the
    *                   getInstance method will share the same instance of the QueryEngine class.
    *
    * @returns          Reference to a QueryEngine object
    */
    static QueryEngine& getInstance() {
        static QueryEngine q;
        return q;
    }

    /**
    * @brief            Set SensorNavigator object
    *
    *                   This method sets the internal SensorNavigator object that can be used by other entities to
    *                   navigate the current sensor structure.
    *
    * @param navi       Pointer to a SensorNavigator object
    */
49
50
51
52
53
54
55
56
57
58
59
    void  setNavigator(shared_ptr<SensorNavigator> navi)         { _navigator = navi; }

    /**
    * @brief            Set the current sensor hierarchy
    *
    *                   This method sets the internal string used to build the sensor tree in the Sensor Navigator.
    *                   This is used for convenience, so that access to the global settings is not necessary.
    *
    * @param hierarchy  String containing a sensor hierarchy
    */
    void  setSensorHierarchy(const string& hierarchy)            { _sensorHierarchy = hierarchy; }
Alessio Netti's avatar
Alessio Netti committed
60
61
62
63
64
65
66
67
68
69
70

    /**
    * @brief            Sets the internal callback to retrieve sensor data
    *
    *                   This method sets the internal callback that will be used by the QueryEngine to retrieve sensor
    *                   data and thus implement an abstraction layer. The callback must store all values for the input
    *                   sensor name, in the given time range, into the "buffer" vector. If such vector has not been
    *                   supplied (NULL), the callback must allocate and return a new one.
    *
    * @param cb         Pointer to a function of type QueryEngineCallback
    */
71
    void  setQueryCallback(QueryEngineCallback cb)               { _callback = cb; }
Alessio Netti's avatar
Alessio Netti committed
72
73
74
75
76
77

    /**
    * @brief            Returns the internal SensorNavigator objects
    *
    * @return           pointer to a SensorNavigator object
    */
78
79
80
81
82
83
84
85
    const shared_ptr<SensorNavigator> getNavigator()             { return _navigator; }

    /**
    * @brief            Returns the current sensor hierarchy
    *
    * @return           String containing the current sensor hierarchy
    */
    const string&  getSensorHierarchy()                          { return _sensorHierarchy; }
Alessio Netti's avatar
Alessio Netti committed
86
87
88
89
90
91
92
93

    /**
    * @brief            Perform a sensor query
    *
    *                   This method allows to retrieve readings for a certain sensor in a given time range. The input
    *                   "buffer" vector allows to re-use memory over successive readings. Note that in order to use
    *                   this method, a callback must have been set through the setQueryCallback method. If not, this
    *                   method will throw an exception.
94
95
96
97
98
99
100
101
    *                   
    *                   The "rel" argument governs how the search is performed in local sensor caches: if set to true,
    *                   startTs and endTs indicate relative offsets against the most recent reading, and the returned
    *                   vector is a view of the cache whose range is computed statically in O(1), and therefore the
    *                   underlying data may be slightly unaligned depending on the sampling rate. If rel is set to
    *                   false, startTs and endTs are interpreted as absolute timestamps, and the cache view is 
    *                   determined by performing binary search with O(log(n)) complexity, thus resulting in a accurate 
    *                   time range. This parameter does not affect the query method when using the Cassandra datastore.
Alessio Netti's avatar
Alessio Netti committed
102
103
104
105
106
    *
    * @param name       Name of the sensor to be queried
    * @param startTs    Start timestamp (in nanoseconds) of the time range for the query
    * @param endTs      End timestamp (in nanoseconds) of the time range for the query. Must be >= startTs
    * @param buffer     Vector in which readings must be stored. If NULL, a new vector will be allocated
107
    * @param true       If true, the input timestamps are considered to be relative offset against "now"
Alessio Netti's avatar
Alessio Netti committed
108
109
    * @return           Pointer to a vector containing readings for the given query
    */
110
    vector<reading_t>* querySensor(const string& name, const uint64_t startTs, const uint64_t endTs, vector<reading_t>* buffer, const bool rel=true) {
Alessio Netti's avatar
Alessio Netti committed
111
112
        if(!_callback)
            throw runtime_error("Query Engine: callback not set!");
Alessio Netti's avatar
Alessio Netti committed
113
        if((startTs > endTs && !rel) || (startTs < endTs && rel))
Alessio Netti's avatar
Alessio Netti committed
114
            throw invalid_argument("Query Engine: invalid time range!");
115
        return _callback(name, startTs, endTs, buffer, rel);
Alessio Netti's avatar
Alessio Netti committed
116
117
    }

Alessio Netti's avatar
Alessio Netti committed
118
119
120
121
122
123
124
125
    void triggerUpdate() {
        updating.store(false);
        updated.store(true);
    }

    //Internal boolean flags used for utility purposes
    atomic<bool> updated;
    atomic<bool> updating;
126

Alessio Netti's avatar
Alessio Netti committed
127
128
129
130
131
132
133
134
private:

    /**
    * @brief            Private class constructor
    */
    QueryEngine() {
        _navigator = NULL;
        _callback = NULL;
Alessio Netti's avatar
Alessio Netti committed
135
136
        updated.store(false);
        updating.store(false);
Alessio Netti's avatar
Alessio Netti committed
137
138
139
140
141
142
143
144
145
146
147
148
149
    }

    /**
    * @brief            Copy constructor is not available
    */
    QueryEngine(QueryEngine const&)     = delete;

    /**
    * @brief            Assignment operator is not available
    */
    void operator=(QueryEngine const&)  = delete;

    // Internal pointer to a SensorNavigator
150
    shared_ptr<SensorNavigator> _navigator;
Alessio Netti's avatar
Alessio Netti committed
151
152
    // Callback used to retrieve sensor data
    QueryEngineCallback _callback;
153
154
    // String storing the current sensor hierarchy, used for convenience
    string _sensorHierarchy;
Alessio Netti's avatar
Alessio Netti committed
155
156
157
};

#endif //PROJECT_QUERYENGINE_H