Fawkes API Fawkes Development Version
computables_manager.cpp
1/***************************************************************************
2 * computables_manager.cpp - Class managing registered computables and
3 * checking if any computables are invoced by a query
4 *
5 * Created: 6:37:45 PM 2016
6 * Copyright 2016 Frederik Zwilling
7 ****************************************************************************/
8
9/* This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Library General Public License for more details.
18 *
19 * Read the full text in the LICENSE.GPL file in the doc directory.
20 */
21
22#include "computables_manager.h"
23
24#include <core/exception.h>
25#ifdef USE_TIMETRACKER
26# include <utils/time/tracker.h>
27#endif
28#include <plugins/robot-memory/robot_memory.h>
29#include <utils/time/tracker_macros.h>
30
31#include <chrono>
32#include <mongocxx/exception/operation_exception.hpp>
33
34/** @class ComputablesManager computables_manager.h
35 * This class manages registering computables and can check
36 * if any computables are invoced by a query.
37 * @author Frederik Zwilling
38 */
39
40using namespace fawkes;
41using namespace mongocxx;
42using namespace bsoncxx;
43
44/**
45 * Constructor for class managing computables with refereces to plugin objects
46 * @param config Configuration
47 * @param robot_memory Robot Memory
48 */
50: config_(config),
51 robot_memory_(robot_memory),
52 matching_test_collection_("robmem.computables_matching")
53{
54 try {
55 matching_test_collection_ =
56 config_->get_string("/plugins/robot-memory/database") + ".computables_matching";
57 } catch (Exception &e) {
58 }
59
60 srand(time(NULL));
61#ifdef USE_TIMETRACKER
62 tt_ = new TimeTracker();
63 tt_loopcount_ = 0;
64 ttc_cleanup_ = tt_->add_class("RobotMemory Cleanup Function Call");
65 ttc_cleanup_inner_loop_ = tt_->add_class("RobotMemory Cleanup Inner Loop");
66 ttc_cleanup_remove_query_ = tt_->add_class("RobotMemory Cleanup Database Remove Query");
67#endif
68}
69
70/**
71 * Copy-construct a ComputablesManager.
72 * Do *not* copy-construct the computables that are managed by the manager, but
73 * only call the constructor with the other's config and robot memory.
74 * If you want to use a computable with the new manager, you will need to
75 * register it again.
76 * @param other A reference to the other ComputablesManager to copy from.
77 */
79: ComputablesManager(other.config_, other.robot_memory_)
80{
81}
82
83ComputablesManager::~ComputablesManager()
84{
85#ifdef USE_TIMETRACKER
86 delete tt_;
87#endif
88}
89
90/**
91 * Remove previously registered computable
92 * @param computable The computable to remove
93 */
94void
96{
97 for (std::list<Computable *>::iterator it = computables.begin(); it != computables.end(); ++it) {
98 if ((*it) == computable) {
99 Computable *comp = *it;
100 computables.erase(it);
101 delete comp;
102 return;
103 }
104 }
105}
106
107/**
108 * Checks if computable knowledge is queried and calls the compute functions in this case
109 * @param query The query that might ask for computable knowledge
110 * @param collection The collection that is querried
111 * @return Were computed documents added?
112 */
113bool
114ComputablesManager::check_and_compute(const document::view &query, std::string collection)
115{
116 //check if computation result of the query is already cached
117 for (std::map<std::tuple<std::string, std::string>, long long>::iterator it =
118 cached_querries_.begin();
119 it != cached_querries_.end();
120 ++it) {
121 if (collection == std::get<0>(it->first) && to_json(query) == std::get<1>(it->first)) {
122 return false;
123 }
124 }
125 if (collection.find(matching_test_collection_) != std::string::npos)
126 return false; //not necessary for matching test itself
127 bool added_computed_docs = false;
128 //check if the query is matched by the computable identifyer
129 //to do that we just insert the query as if it would be a document and query for it with the computable identifiers
130 std::string current_test_collection = matching_test_collection_ + std::to_string(rand());
131 try {
132 robot_memory_->insert(query, current_test_collection);
133 } catch (mongocxx::operation_exception &e) {
134 // This may happen if the query contains fields that cannot be inserted, e.g., a $regex
135 robot_memory_->drop_collection(current_test_collection);
136 return false;
137 }
138 for (std::list<Computable *>::iterator it = computables.begin(); it != computables.end(); ++it) {
139 auto cursor = robot_memory_->query((*it)->get_query(), current_test_collection);
140 if (collection == (*it)->get_collection() && cursor.begin() != cursor.end()) {
141 std::list<document::value> computed_docs_list = (*it)->compute(query);
142 if (!computed_docs_list.empty()) {
143 //move list into vector
144 std::vector<document::view> computed_docs_vector{
145 std::make_move_iterator(std::begin(computed_docs_list)),
146 std::make_move_iterator(std::end(computed_docs_list))};
147 //remember how long a query is cached:
148 long long cached_until =
149 computed_docs_vector[0]["_robmem_info"]["cached_until"].get_int64();
150 cached_querries_[std::make_tuple(collection, to_json(query))] = cached_until;
151 //TODO: fix minor problem: equivalent queries in different order jield unequal strings
152 robot_memory_->insert(computed_docs_vector, (*it)->get_collection());
153 added_computed_docs = true;
154 }
155 }
156 }
157 robot_memory_->drop_collection(current_test_collection);
158 return added_computed_docs;
159}
160
161/**
162 * Clean up all collections containing documents computed on demand
163 */
164void
166{
167 TIMETRACK_START(ttc_cleanup_);
168 long long current_time_ms =
169 std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1);
170 for (std::map<std::tuple<std::string, std::string>, long long>::iterator it =
171 cached_querries_.begin();
172 it != cached_querries_.end();
173 ++it) {
174 TIMETRACK_START(ttc_cleanup_inner_loop_);
175 if (current_time_ms > it->second) {
176 using namespace bsoncxx::builder;
177 basic::document doc;
178 doc.append(basic::kvp("_robmem_info.computed", true));
179 doc.append(
180 basic::kvp("_robmem_info.cached_until", [current_time_ms](basic::sub_document subdoc) {
181 subdoc.append(basic::kvp("$lt", static_cast<std::int64_t>(current_time_ms)));
182 }));
183 TIMETRACK_START(ttc_cleanup_remove_query_);
184 robot_memory_->remove(doc, std::get<0>(it->first));
185 TIMETRACK_END(ttc_cleanup_remove_query_);
186 cached_querries_.erase(it->first);
187 }
188 TIMETRACK_END(ttc_cleanup_inner_loop_);
189 }
190 TIMETRACK_END(ttc_cleanup_);
191#ifdef USE_TIMETRACKER
192 if (++tt_loopcount_ % 5 == 0) {
193 tt_->print_to_stdout();
194 }
195#endif
196}
Class holding information for a single computable this class also enhances computed documents by addi...
Definition: computable.h:32
This class manages registering computables and can check if any computables are invoced by a query.
void cleanup_computed_docs()
Clean up all collections containing documents computed on demand.
void remove_computable(Computable *computable)
Remove previously registered computable.
ComputablesManager(fawkes::Configuration *config, RobotMemory *robot_memory)
Constructor for class managing computables with refereces to plugin objects.
bool check_and_compute(const bsoncxx::document::view &query, std::string collection)
Checks if computable knowledge is queried and calls the compute functions in this case.
Access to the robot memory based on mongodb.
Definition: robot_memory.h:47
mongocxx::cursor query(bsoncxx::document::view query, const std::string &collection_name="", mongocxx::options::find query_options=mongocxx::options::find())
Query information from the robot memory.
int remove(const bsoncxx::document::view &query, const std::string &collection="")
Remove documents from the robot memory.
int insert(bsoncxx::document::view, const std::string &collection="")
Inserts a document into the robot memory.
int drop_collection(const std::string &collection)
Drop (= remove) a whole collection and all documents inside it.
Interface for configuration handling.
Definition: config.h:68
virtual std::string get_string(const char *path)=0
Get value from configuration which is of type string.
Base class for exceptions in Fawkes.
Definition: exception.h:36
Time tracking utility.
Definition: tracker.h:37
Fawkes library namespace.