Skip to content

Commit

Permalink
Add check_cacher. (envoyproxy#13)
Browse files Browse the repository at this point in the history
* Add check_cacher.

* Remove unused functions.

* Rename class CheckCacher to CheckCache.
  • Loading branch information
chowchow316 authored and qiwzhang committed Jan 24, 2017
1 parent 1e8b001 commit 2fcb1fb
Show file tree
Hide file tree
Showing 5 changed files with 496 additions and 0 deletions.
14 changes: 14 additions & 0 deletions mixerclient/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ cc_library(
"src/attribute_context.cc",
"src/attribute_context.h",
"src/attribute_converter.h",
"src/check_cache.cc",
"src/check_cache.h",
"src/client_impl.cc",
"src/client_impl.h",
"src/signature.cc",
Expand All @@ -30,6 +32,7 @@ cc_library(
"src/transport.h",
"utils/md5.cc",
"utils/md5.h",
"utils/status_test_util.h",
],
hdrs = [
"include/client.h",
Expand All @@ -38,6 +41,7 @@ cc_library(
],
visibility = ["//visibility:public"],
deps = [
":simple_lru_cache",
"//external:boringssl_crypto",
"//external:mixer_api_cc_proto",
],
Expand Down Expand Up @@ -108,3 +112,13 @@ cc_test(
"//external:googletest_main",
],
)

cc_test(
name = "check_cache_test",
size = "small",
srcs = ["src/check_cache_test.cc"],
deps = [
":mixer_client_lib",
"//external:googletest_main",
],
)
128 changes: 128 additions & 0 deletions mixerclient/src/check_cache.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/* Copyright 2017 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "src/check_cache.h"
#include "src/signature.h"

#include "google/protobuf/stubs/logging.h"

using std::string;
using ::istio::mixer::v1::CheckRequest;
using ::istio::mixer::v1::CheckResponse;
using ::google::protobuf::util::Status;
using ::google::protobuf::util::error::Code;

namespace istio {
namespace mixer_client {

CheckCache::CheckCache(const CheckOptions& options) : options_(options) {
// Converts flush_interval_ms to Cycle used by SimpleCycleTimer.
flush_interval_in_cycle_ =
options_.flush_interval_ms * SimpleCycleTimer::Frequency() / 1000;

if (options.num_entries >= 0) {
cache_.reset(new CheckLRUCache(
options.num_entries, std::bind(&CheckCache::OnCacheEntryDelete, this,
std::placeholders::_1)));
cache_->SetMaxIdleSeconds(options.expiration_ms / 1000.0);
}
}

CheckCache::~CheckCache() {
// FlushAll() will remove all cache items.
FlushAll();
}

bool CheckCache::ShouldFlush(const CacheElem& elem) {
int64_t age = SimpleCycleTimer::Now() - elem.last_check_time();
return age >= flush_interval_in_cycle_;
}

Status CheckCache::Check(const Attributes& attributes,
CheckResponse* response) {
string request_signature = GenerateSignature(attributes);
std::unique_lock<std::mutex> lock(cache_mutex_);
CheckLRUCache::ScopedLookup lookup(cache_.get(), request_signature);

if (!lookup.Found()) {
// By returning NO_FOUND, caller will send request to server.
return Status(Code::NOT_FOUND, "");
}

CacheElem* elem = lookup.value();

if (ShouldFlush(*elem)) {
// Setting last check to now to block more check requests to Mixer.
elem->set_last_check_time(SimpleCycleTimer::Now());
// By returning NO_FOUND, caller will send request to server.
return Status(Code::NOT_FOUND, "");
}

*response = elem->check_response();

return Status::OK;
}

Status CheckCache::CacheResponse(const Attributes& attributes,
const CheckResponse& response) {
std::unique_lock<std::mutex> lock(cache_mutex_);

if (cache_) {
string request_signature = GenerateSignature(attributes);
CheckLRUCache::ScopedLookup lookup(cache_.get(), request_signature);

int64_t now = SimpleCycleTimer::Now();

if (lookup.Found()) {
lookup.value()->set_last_check_time(now);
lookup.value()->set_check_response(response);
} else {
CacheElem* cache_elem = new CacheElem(response, now);
cache_->Insert(request_signature, cache_elem, 1);
}
}

return Status::OK;
}

// Flush aggregated requests whom are longer than flush_interval.
// Called at time specified by GetNextFlushInterval().
Status CheckCache::Flush() {
std::unique_lock<std::mutex> lock(cache_mutex_);

if (cache_) {
cache_->RemoveExpiredEntries();
}

return Status::OK;
}

void CheckCache::OnCacheEntryDelete(CacheElem* elem) { delete elem; }

// Flush out aggregated check requests, clear all cache items.
// Usually called at destructor.
Status CheckCache::FlushAll() {
GOOGLE_LOG(INFO) << "Remove all entries of check cache.";
std::unique_lock<std::mutex> lock(cache_mutex_);

if (cache_) {
cache_->RemoveAll();
}

return Status::OK;
}

} // namespace mixer_client
} // namespace istio
136 changes: 136 additions & 0 deletions mixerclient/src/check_cache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/* Copyright 2017 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// Caches check attributes.

#ifndef MIXERCLIENT_CHECK_CACHE_H
#define MIXERCLIENT_CHECK_CACHE_H

#include <mutex>
#include <string>
#include <unordered_map>
#include <utility>

#include "google/protobuf/stubs/status.h"
#include "include/client.h"
#include "include/options.h"
#include "mixer/api/v1/service.pb.h"
#include "utils/simple_lru_cache.h"
#include "utils/simple_lru_cache_inl.h"

namespace istio {
namespace mixer_client {

// Cache Mixer Check Attributes.
// This interface is thread safe.
class CheckCache {
public:
CheckCache(const CheckOptions& options);

virtual ~CheckCache();

// If the check could not be handled by the cache, returns NOT_FOUND,
// caller has to send the request to mixer.
// Otherwise, returns OK and cached response.
virtual ::google::protobuf::util::Status Check(
const Attributes& request, ::istio::mixer::v1::CheckResponse* response);

// Caches a response from a remote mixer call.
virtual ::google::protobuf::util::Status CacheResponse(
const Attributes& request,
const ::istio::mixer::v1::CheckResponse& response);

// Invalidates expired check responses.
// Called at time specified by GetNextFlushInterval().
virtual ::google::protobuf::util::Status Flush();

// Flushes out all cached check responses; clears all cache items.
// Usually called at destructor.
virtual ::google::protobuf::util::Status FlushAll();

private:
class CacheElem {
public:
CacheElem(const ::istio::mixer::v1::CheckResponse& response,
const int64_t time)
: check_response_(response), last_check_time_(time) {}

// Setter for check response.
inline void set_check_response(
const ::istio::mixer::v1::CheckResponse& check_response) {
check_response_ = check_response;
}
// Getter for check response.
inline const ::istio::mixer::v1::CheckResponse& check_response() const {
return check_response_;
}

// Setter for last check time.
inline void set_last_check_time(const int64_t last_check_time) {
last_check_time_ = last_check_time;
}
// Getter for last check time.
inline const int64_t last_check_time() const { return last_check_time_; }

private:
// The check response for the last check request.
::istio::mixer::v1::CheckResponse check_response_;
// In general, this is the last time a check response is updated.
//
// During flush, we set it to be the request start time to prevent a next
// check request from triggering another flush. Note that this prevention
// works only during the flush interval, which means for long RPC, there
// could be up to RPC_time/flush_interval ongoing check requests.
int64_t last_check_time_;
};

using CacheDeleter = std::function<void(CacheElem*)>;
// Key is the signature of the Attributes. Value is the CacheElem.
// It is a LRU cache with MaxIdelTime as response_expiration_time.
using CheckLRUCache =
SimpleLRUCacheWithDeleter<std::string, CacheElem, CacheDeleter>;

// Returns whether we should flush a cache entry.
// If the aggregated check request is less than flush interval, no need to
// flush.
bool ShouldFlush(const CacheElem& elem);

// Flushes the internal operation in the elem and delete the elem. The
// response from the server is NOT cached.
// Takes ownership of the elem.
void OnCacheEntryDelete(CacheElem* elem);

// The check options.
CheckOptions options_;

// Mutex guarding the access of cache_;
std::mutex cache_mutex_;

// The cache that maps from operation signature to an operation.
// We don't calculate fine grained cost for cache entries, assign each
// entry 1 cost unit.
// Guarded by mutex_, except when compare against NULL.
std::unique_ptr<CheckLRUCache> cache_;

// flush interval in cycles.
int64_t flush_interval_in_cycle_;

GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CheckCache);
};

} // namespace mixer_client
} // namespace istio

#endif // MIXERCLIENT_CHECK_CACHE_H
Loading

0 comments on commit 2fcb1fb

Please sign in to comment.