@@ -188,34 +188,56 @@ void stream_info_impl::from_fullinfo_message(const std::string &m) {
188188 read_xml (doc_);
189189}
190190
191- /* *
192- * Test whether this stream info matches the given query string.
193- */
194- bool stream_info_impl::matches_query (const string &query) {
191+ // / Test whether this stream info matches the given query string.
192+ bool stream_info_impl::matches_query (const string &query, bool nocache) {
193+ return cached_.matches_query (doc_, query, nocache);
194+ }
195+
196+ bool query_cache::matches_query (const xml_document &doc, const std::string query, bool nocache) {
195197 lslboost::lock_guard<lslboost::mutex> lock (cache_mut_);
196- query_cache::left_iterator it = cached_.left .find (query);
197- if (it != cached_.left .end ()) {
198- // found in cache
199- bool is_match = it->second .second ;
198+
199+ decltype (cache)::iterator it;
200+ if (!nocache && (it = cache.find (query)) != cache.end ()) {
201+ // the sign bit encodes if the query matches or not
202+ bool matches = it->second > 0 ;
200203 // update the last-use time stamp
201- cached_.left .replace_data (it,std::make_pair (lsl_clock (),is_match));
202- return is_match;
203- } else {
204- // not found in cache
205- try {
206- // compute whether it matches
207- string fullquery = (string (" /info[" ) += query) += " ]" ;
208- bool result = !doc_.select_nodes (fullquery.c_str ()).empty ();
209- // insert result into cache
210- cached_.left .insert (std::make_pair (query,std::make_pair (lsl_clock (),result)));
211- // remove oldest results until we're within capacity
212- while ((int )cached_.size () > api_config::get_instance ()->max_cached_queries ())
213- cached_.right .erase (cached_.right .begin ());
214- // return result
215- return result;
216- } catch (...) {
217- return false ; // error: unsupported query
204+ it->second = ++query_cache_age * (matches ? 1 : -1 );
205+ // return cached match
206+ return matches;
207+ }
208+
209+ // not found in cache
210+ try {
211+ // compute whether it matches
212+ bool matched = pugi::xpath_query (query.c_str ()).evaluate_boolean (doc.first_child ());
213+
214+ auto max_cached = (std::size_t )api_config::get_instance ()->max_cached_queries ();
215+ if (nocache || max_cached == 0 )
216+ return matched;
217+
218+ cache.insert (std::make_pair (query, ++query_cache_age * (matched ? 1 : -1 )));
219+
220+ // remove n/2 oldest results to make room for new entries
221+ if (cache.size () > max_cached) {
222+ // Find out the median cache entry age
223+ std::vector<int > agevec;
224+ agevec.reserve (cache.size ());
225+ for (auto &val : cache) agevec.push_back (std::abs (val.second ));
226+ auto middle = agevec.begin () + max_cached / 2 ;
227+ std::nth_element (agevec.begin (), middle, agevec.end ());
228+ auto oldest_to_keep = *middle;
229+
230+ // Remove all elements older than the median age
231+ for (auto it = cache.begin (); it != cache.end ();)
232+ if (abs (it->second ) <= oldest_to_keep)
233+ it = cache.erase (it);
234+ else
235+ ++it;
218236 }
237+ return matched;
238+ } catch (std::exception &e) {
239+ LOG_F (WARNING, " Query error: %s" , e.what ());
240+ return false ;
219241 }
220242}
221243
0 commit comments