/src/client-common/cache/CapacityCache.cpp

https://gitlab.com/github-cloud-corporation/cynara · C++ · 171 lines · 118 code · 27 blank · 26 comment · 21 complexity · fd5078875d5bf38e0d2542b307d0fe42 MD5 · raw file

  1. /*
  2. * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License
  15. */
  16. /**
  17. * @file src/client-common/cache/CapacityCache.cpp
  18. * @author Zofia Abramowska <z.abramowska@samsung.com>
  19. * @version 1.0
  20. * @brief This file contains capacity cache implementation.
  21. */
  22. #include <cinttypes>
  23. #include <cynara-error.h>
  24. #include <log/log.h>
  25. #include <cache/CapacityCache.h>
  26. namespace Cynara {
  27. CapacityCache::CapacityCache(std::size_t capacity) : m_capacity(capacity),
  28. m_pluginManager(PathConfig::PluginPath::clientDir) {
  29. m_pluginManager.loadPlugins();
  30. }
  31. int CapacityCache::get(const ClientSession &session, const PolicyKey &key) {
  32. auto resultIt = m_keyValue.find(keyToString(key));
  33. //Do we have entry in cache?
  34. if (resultIt == m_keyValue.end()) {
  35. LOGD("No entry for client=%s user=%s privilege=%s.",
  36. key.client().toString().c_str(),
  37. key.user().toString().c_str(),
  38. key.privilege().toString().c_str());
  39. return CYNARA_API_CACHE_MISS;
  40. } else {
  41. LOGD("Entry available for client=%s user=%s privilege=%s",
  42. key.client().toString().c_str(),
  43. key.user().toString().c_str(),
  44. key.privilege().toString().c_str());
  45. auto &cachedValue = resultIt->second;
  46. auto &policyResult = std::get<0>(cachedValue);
  47. ClientPluginInterfacePtr plugin = findPlugin(policyResult.policyType());
  48. if (!plugin) {
  49. LOGE("No plugin registered for given policyType: [%" PRIu16 "]",
  50. policyResult.policyType());
  51. return CYNARA_API_ACCESS_DENIED;
  52. }
  53. //Is it still usable?
  54. auto &prevSession = std::get<1>(cachedValue);
  55. auto usageIt = std::get<2>(cachedValue);
  56. bool updateSession = false;
  57. if (plugin->isUsable(session, prevSession, updateSession, policyResult)) {
  58. LOGD("Entry usable.");
  59. m_keyUsage.splice(m_keyUsage.begin(), m_keyUsage, usageIt);
  60. if (updateSession) {
  61. prevSession = session;
  62. }
  63. return plugin->toResult(session, policyResult);
  64. }
  65. //Remove unusable entry
  66. LOGD("Entry not usable");
  67. m_keyUsage.erase(usageIt);
  68. m_keyValue.erase(resultIt);
  69. return CYNARA_API_CACHE_MISS;
  70. }
  71. }
  72. void CapacityCache::clear(void) {
  73. m_keyUsage.clear();
  74. m_keyValue.clear();
  75. m_pluginManager.invalidateAll();
  76. for (auto &plugin : m_plugins) {
  77. plugin.second->invalidate();
  78. }
  79. }
  80. std::string CapacityCache::keyToString(const PolicyKey &key) {
  81. const char separator = '\1';
  82. auto clientStr = key.client().toString();
  83. auto privilegeStr = key.privilege().toString();
  84. auto userStr = key.user().toString();
  85. return clientStr + privilegeStr + userStr + separator +
  86. std::to_string(clientStr.size()) + separator +
  87. std::to_string(privilegeStr.size()) + separator +
  88. std::to_string(userStr.size());
  89. }
  90. void CapacityCache::evict(void) {
  91. auto lastUsedKey = m_keyUsage.back();
  92. m_keyUsage.pop_back();
  93. auto value_it = m_keyValue.find(lastUsedKey);
  94. m_keyValue.erase(value_it);
  95. }
  96. int CapacityCache::update(const ClientSession &session,
  97. const PolicyKey &key,
  98. const PolicyResult &result) {
  99. ClientPluginInterfacePtr plugin = findPlugin(result.policyType());
  100. if (!plugin) {
  101. LOGE("No plugin registered for given policyType: [%" PRIu16 "]", result.policyType());
  102. return CYNARA_API_ACCESS_DENIED;
  103. }
  104. PolicyResult storedResult = result;
  105. if (m_capacity > 0) {
  106. std::string cacheKey = keyToString(key);
  107. auto resultIt = m_keyValue.find(cacheKey);
  108. if (plugin->isCacheable(session, storedResult)) {
  109. LOGD("Entry cacheable");
  110. if (m_keyValue.size() == m_capacity) {
  111. LOGD("Capacity reached.");
  112. evict();
  113. }
  114. //Move value usage to front
  115. if (resultIt != m_keyValue.end()) {
  116. auto usageIt = std::get<2>(resultIt->second);
  117. m_keyUsage.splice(m_keyUsage.begin(), m_keyUsage, usageIt);
  118. } else {
  119. m_keyUsage.push_front(cacheKey);
  120. }
  121. m_keyValue[cacheKey] = std::make_tuple(storedResult, session, m_keyUsage.begin());
  122. } else {
  123. //Remove element
  124. if (resultIt != m_keyValue.end()) {
  125. auto usageIt = std::get<2>(resultIt->second);
  126. m_keyUsage.erase(usageIt);
  127. m_keyValue.erase(resultIt);
  128. }
  129. }
  130. }
  131. return plugin->toResult(session, storedResult);
  132. }
  133. ClientPluginInterfacePtr CapacityCache::findPlugin(PolicyType policyType) {
  134. ClientPluginInterfacePtr plugin;
  135. auto pluginIt = m_plugins.find(policyType);
  136. if (pluginIt != m_plugins.end()) {
  137. plugin = pluginIt->second;
  138. } else {
  139. plugin = std::dynamic_pointer_cast<ClientPluginInterface>(
  140. m_pluginManager.getPlugin(policyType));
  141. }
  142. return plugin;
  143. }
  144. } // namespace Cynara