Merge "serialization: serialize send index" into tizen_5.5
[platform/core/system/libdbuspolicy.git] / src / internal / storage_backend_serialized.cpp
index cf37c6b..5271adf 100644 (file)
@@ -24,6 +24,7 @@
 #include <cerrno>
 #include <fcntl.h>
 #include <map>
+#include <string>
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -133,27 +134,13 @@ class StorageBackendSerialized::StorageBackendSerializedImpl {
        void releaseMMap();
        void releaseFD();
 
-       typedef std::pair<const ItemSend *, unsigned> ItemWithScore;    // a pair: Item, index of Item
-       typedef std::vector<ItemWithScore> ItemsWithScore;                              // items
-       typedef std::pair<unsigned, ItemsWithScore> HighestScoreWithItems;      // value for index map: highest index for items, items
-       typedef std::map<boost::string_ref, HighestScoreWithItems> MapIndex;
-       typedef std::vector<ItemWithScore> SendPrefixIndex;
-
-       MapIndex sendIndex; // context default
-       SendPrefixIndex sendPrefixIndex; // context default prefix rules
-       std::map<uid_t, MapIndex> userSendIndex;
-       std::map<uid_t, SendPrefixIndex> userSendPrefixIndex;
-
 public:
        bool init(const char *filename, bool verify);
        bool init(const FB::File *f);
        bool initFromXML(const char *config_name);
        void release();
 
-       void createSendIndex();
-       ldp_xml_parser::DecisionItem getDecisionFromSendIndex(const MatchItemSend &item, const MapIndex &index, const SendPrefixIndex &prefixIndex);
-       ldp_xml_parser::DecisionItem getDecisionFromSendIndex(const MatchItemSend &item);
-       ldp_xml_parser::DecisionItem getDecisionFromSendIndex(const MatchItemSend &item, uid_t uid);
+       ldp_xml_parser::DecisionItem getDecisionFromSendIndex(const MatchItemSend &item, const FB::PolicySend *policy);
 
        void printContent(const bool xml_format = false) const;
 
@@ -162,90 +149,72 @@ public:
 };
 
 ldp_xml_parser::DecisionItem StorageBackendSerialized::StorageBackendSerializedImpl::getDecisionFromSendIndex(const MatchItemSend &item,
-               const MapIndex &index, const SendPrefixIndex &prefixIndex) {
-       ldp_xml_parser::DecisionItem decision(ldp_xml_parser::Decision::ANY);
+               const FB::PolicySend *policy) {
+
+       const auto *index = policy->index();
+
+       if (!index || index->size() == 0)           // this indicates version earlier than LDP2
+               return getDecisionItem(item, policy);   // make it old way for old databases
+
+       std::pair<const ItemSend*, uint32_t> currentBest(nullptr, 0);
+
+       auto updateCurrentBest = [&currentBest, &item, &policy](const flatbuffers::Vector<uint32_t> *vec) {
+               // look from the back, the rule is the same as for the full database
+               // we now only check among less elements, because the database is indexed to small lists
+               // item_scores are in increasing order in the index, and they serve also as ids of the policy rules
+               for (auto item_score_it = vec->rbegin(); item_score_it != vec->rend(); item_score_it++) {
+                       const auto *fb_item = policy->items()->Get(*item_score_it - 1); // rules are indexed/scored from 1
+                       if (*item_score_it > currentBest.second && match(item, fb_item)) {
+                               currentBest.first = fb_item;
+                               currentBest.second = *item_score_it;
+                               return;
+                       } else if (*item_score_it <= currentBest.second) {
+                               // there is no need to look further as we can't improve the score anymore
+                               return;
+                       }
+               }
+       };
 
-       ItemWithScore currentBest(nullptr, 0);
+       auto searchAndUpdateCurrentBest = [&currentBest, &index, &updateCurrentBest](boost::string_ref name_ref) {
+               // we need to create C-string for flatbuffers lookups
+               // boost::string_ref gives us correct start, but possibly NUL-terminated in a wrong place, as it does not modify
+               // input string and keeps only the length
+               std::string name(name_ref.data(), name_ref.size());
 
-       auto updateCurrentBest = [&currentBest, &item, &index](boost::string_ref name) {
                // check if there are any rules for the name
-               auto fit = index.find(name);
-               if (fit == index.end())
+               const auto *fit = index->LookupByKey(name.c_str());
+               if (!fit)
                        return;
 
                // check if there's any chance to get better score
-               // fit->second.first is the highest score from vector fit->second.second
-               if (fit->second.first <= currentBest.second)
+               if (fit->best_score() <= currentBest.second)
                        return;
 
                // look for better score
-               for (const auto &it: fit->second.second) {
-                       if (it.second > currentBest.second && match(item, it.first))
-                               currentBest = it;
-               }
+               updateCurrentBest(fit->item_refs());
        };
 
+       const auto *prefixIndex = policy->prefix_index();
+       assert(prefixIndex);
+
        // iterate over names
        for (const auto &name: item.getNames()) {
                // find and check the no-prefix rules
-               updateCurrentBest(name);
+               searchAndUpdateCurrentBest(name);
 
                // check the prefix rules
-               for (const auto &prefixItem: prefixIndex) {
-                       if (prefixItem.second > currentBest.second && match(item, prefixItem.first))
-                               currentBest = prefixItem;
-               }
+               updateCurrentBest(prefixIndex);
        }
 
        // check no-name rules
-       updateCurrentBest("");
+       searchAndUpdateCurrentBest("");
 
+       // if a matching rule was found, return the decision
        if (currentBest.first)
-               decision = makeDecisionItem(currentBest.first->decision());
-
-       return decision;
-}
+               return makeDecisionItem(currentBest.first->decision());
 
-ldp_xml_parser::DecisionItem StorageBackendSerialized::StorageBackendSerializedImpl::getDecisionFromSendIndex(const MatchItemSend &item) {
-       return getDecisionFromSendIndex(item, sendIndex, sendPrefixIndex);
-}
-
-ldp_xml_parser::DecisionItem StorageBackendSerialized::StorageBackendSerializedImpl::getDecisionFromSendIndex(const MatchItemSend &item, uid_t uid) {
-       return getDecisionFromSendIndex(item, userSendIndex[uid], userSendPrefixIndex[uid]);
-}
-
-void StorageBackendSerialized::StorageBackendSerializedImpl::createSendIndex() {
-       // helper for adding items to indexes
-       auto add = [](MapIndex &index, SendPrefixIndex &prefixIndex, boost::string_ref key, ItemWithScore value) {
-               if (value.first->is_name_prefix()) {
-                       prefixIndex.push_back(value);
-               } else {
-                       index[key].second.push_back(value);
-                       // we insert items in increasing score order, so we just update the highest score on each add
-                       index[key].first = value.second;
-               }
-       };
-
-       // context default index
-       const auto *policy = file->m_send_set()->context_default();
-       unsigned cnt = 1;
-
-       const auto *v = policy->items();
-       for (auto it = v->begin(); it != v->end(); ++it)
-               add(sendIndex, sendPrefixIndex,
-                               boost::string_ref(it->name()->c_str(), it->name()->size()),
-                               ItemWithScore(*it, cnt++));
-
-       // users index
-       for (const auto &uidPolicy: *file->m_send_set()->user()) {
-               cnt = 1;
-               for (const auto it: *uidPolicy->policy()->items()) {
-                       add(userSendIndex[uidPolicy->id()],
-                                       userSendPrefixIndex[uidPolicy->id()],
-                                       boost::string_ref(it->name()->c_str(), it->name()->size()),
-                                       ItemWithScore(it, cnt++));
-               }
-       }
+       // or if no matching rule was not found, return the default decision
+       return ldp_xml_parser::DecisionItem(ldp_xml_parser::Decision::ANY);
 }
 
 void StorageBackendSerialized::StorageBackendSerializedImpl::releaseMMap() {
@@ -324,17 +293,13 @@ bool StorageBackendSerialized::StorageBackendSerializedImpl::init(const char *fi
        mmapGuard.dismiss();
 
        file = GetFile(mem);
-       bool res = file != nullptr;
-       if (res)
-               createSendIndex();
-       return res;
+       return file != nullptr;
 }
 
 bool StorageBackendSerialized::StorageBackendSerializedImpl::init(const FB::File *f) {
        assert(nullptr == file);
 
        file = f;
-       createSendIndex();
        return true;
 }
 
@@ -403,8 +368,13 @@ ldp_xml_parser::DecisionItem StorageBackendSerialized::getDecisionItemContextMan
 }
 
 template <>
+ldp_xml_parser::DecisionItem StorageBackendSerialized::getDecisionItemContextMandatory(const MatchItemSend &item) const {
+       return pimpl->getDecisionFromSendIndex(item, pimpl->getPolicySet<MatchItemSend>()->context_mandatory());
+}
+
+template <>
 ldp_xml_parser::DecisionItem StorageBackendSerialized::getDecisionItemContextDefault(const MatchItemSend &item) const {
-       return pimpl->getDecisionFromSendIndex(item);
+       return pimpl->getDecisionFromSendIndex(item, pimpl->getPolicySet<MatchItemSend>()->context_default());
 }
 
 template <>
@@ -412,7 +382,7 @@ ldp_xml_parser::DecisionItem StorageBackendSerialized::getDecisionItemUser(uid_t
        auto *policyPair = pimpl->getPolicySet<MatchItemSend>()->user()->LookupByKey(uid);
        if (nullptr == policyPair)
                return ldp_xml_parser::Decision::ANY;
-       return pimpl->getDecisionFromSendIndex(item, uid);
+       return pimpl->getDecisionFromSendIndex(item, policyPair->policy());
 }
 
 template <typename T>