diff --git a/examples/features/client_http_sse_proxy.cc b/examples/features/client_http_sse_proxy.cc new file mode 100644 index 00000000..3e1a2d34 --- /dev/null +++ b/examples/features/client_http_sse_proxy.cc @@ -0,0 +1,5 @@ +#include "http_sse_proxy.h" +void HttpSseProxy::RegisterSseHandler() { + // 这里可以实现 SSE 接口注册逻辑,或转发 HTTP 请求到 LruCacheProxy + // 示例略。 +} diff --git a/examples/features/client_http_sse_proxy.h b/examples/features/client_http_sse_proxy.h new file mode 100644 index 00000000..38281e0f --- /dev/null +++ b/examples/features/client_http_sse_proxy.h @@ -0,0 +1,7 @@ +#pragma once +#include "lru_cache_proxy.h" + +class HttpSseProxy : public LruCacheProxy { + public: + void RegisterSseHandler(); // 可选:注册 SSE 接口到 Web Server +}; diff --git a/examples/features/client_lru_cache_proxy.h b/examples/features/client_lru_cache_proxy.h new file mode 100644 index 00000000..a6810db7 --- /dev/null +++ b/examples/features/client_lru_cache_proxy.h @@ -0,0 +1,15 @@ +#pragma once +#include "proto/lru_cache.pb.h" +#include "proto/lru_cache.trpc.pb.h" +#include "trpc/client/service_proxy.h" + +class LruCacheProxy : public trpc::ServiceProxy { + public: + using PutRequest = trpc::examples::lru::PutRequest; + using PutResponse = trpc::examples::lru::PutResponse; + using GetRequest = trpc::examples::lru::GetRequest; + using GetResponse = trpc::examples::lru::GetResponse; + + TRPC_PROXY_METHOD(trpc::examples::lru::LruCacheService, Put, PutRequest, PutResponse) + TRPC_PROXY_METHOD(trpc::examples::lru::LruCacheService, Get, GetRequest, GetResponse) +}; diff --git a/examples/features/lru_cache.proto b/examples/features/lru_cache.proto new file mode 100644 index 00000000..29ea101e --- /dev/null +++ b/examples/features/lru_cache.proto @@ -0,0 +1,25 @@ +syntax = "proto3"; +package trpc.examples.lru; + +service LruCacheService { + rpc Put (PutRequest) returns (PutResponse); + rpc Get (GetRequest) returns (GetResponse); +} + +message PutRequest { + string key = 1; + bytes value = 2; +} + +message PutResponse { + bool success = 1; +} + +message GetRequest { + string key = 1; +} + +message GetResponse { + bytes value = 1; + bool found = 2; +} diff --git a/examples/features/run.sh b/examples/features/run.sh new file mode 100644 index 00000000..ecc0ad40 --- /dev/null +++ b/examples/features/run.sh @@ -0,0 +1,3 @@ +#!/bin/bash +bazel build //examples/features/lru_cache/server:lru_cache_service +bazel-bin/examples/features/lru_cache/server/lru_cache_service diff --git a/examples/features/server_lru_cache.h b/examples/features/server_lru_cache.h new file mode 100644 index 00000000..6c27bd80 --- /dev/null +++ b/examples/features/server_lru_cache.h @@ -0,0 +1,44 @@ +#pragma once +#include +#include +#include +#include "trpc/util/fiber/fiber_mutex.h" + +template +class LRUCache { + public: + explicit LRUCache(size_t capacity) : capacity_(capacity) {} + + bool Put(const Key& key, const Value& value) { + std::lock_guard lock(mutex_); + auto it = cache_.find(key); + if (it != cache_.end()) { + items_.erase(it->second); + cache_.erase(it); + } + items_.emplace_front(key, value); + cache_[key] = items_.begin(); + if (cache_.size() > capacity_) { + auto last = items_.end(); + last--; + cache_.erase(last->first); + items_.pop_back(); + } + return true; + } + + bool Get(const Key& key, Value& value) { + std::lock_guard lock(mutex_); + auto it = cache_.find(key); + if (it == cache_.end()) return false; + value = it->second->second; + items_.splice(items_.begin(), items_, it->second); + return true; + } + + private: + size_t capacity_; + std::list> items_; + std::unordered_map>::iterator> cache_; + MutexType mutex_; +}; diff --git a/examples/features/server_lru_cache_service.cc b/examples/features/server_lru_cache_service.cc new file mode 100644 index 00000000..e683c24f --- /dev/null +++ b/examples/features/server_lru_cache_service.cc @@ -0,0 +1,18 @@ +#include "lru_cache_service.h" + +trpc::Status LruCacheServiceImpl::Put(trpc::ServerContextPtr, + const trpc::examples::lru::PutRequest* request, + trpc::examples::lru::PutResponse* response) { + response->set_success(cache_.Put(request->key(), request->value())); + return trpc::kSuccStatus; +} + +trpc::Status LruCacheServiceImpl::Get(trpc::ServerContextPtr, + const trpc::examples::lru::GetRequest* request, + trpc::examples::lru::GetResponse* response) { + std::string value; + bool found = cache_.Get(request->key(), value); + response->set_found(found); + if (found) response->set_value(value); + return trpc::kSuccStatus; +} diff --git a/examples/features/server_lru_cache_service.h b/examples/features/server_lru_cache_service.h new file mode 100644 index 00000000..7cebe793 --- /dev/null +++ b/examples/features/server_lru_cache_service.h @@ -0,0 +1,20 @@ +#pragma once +#include "proto/lru_cache.pb.h" +#include "proto/lru_cache.trpc.pb.h" +#include "lru_cache.h" + +class LruCacheServiceImpl : public trpc::examples::lru::LruCacheService { + public: + LruCacheServiceImpl() : cache_(1000) {} + + trpc::Status Put(trpc::ServerContextPtr context, + const trpc::examples::lru::PutRequest* request, + trpc::examples::lru::PutResponse* response) override; + + trpc::Status Get(trpc::ServerContextPtr context, + const trpc::examples::lru::GetRequest* request, + trpc::examples::lru::GetResponse* response) override; + + private: + LRUCache cache_; +}; \ No newline at end of file diff --git a/examples/features/test_lru_cache_test.cc b/examples/features/test_lru_cache_test.cc new file mode 100644 index 00000000..df0c3e8f --- /dev/null +++ b/examples/features/test_lru_cache_test.cc @@ -0,0 +1,13 @@ +#include +#include "server/lru_cache.h" + +TEST(LruCacheTest, PutGetEvict) { + LRUCache cache(2); + cache.Put("a", "1"); + cache.Put("b", "2"); + std::string v; + EXPECT_TRUE(cache.Get("a", v)); + EXPECT_EQ(v, "1"); + cache.Put("c", "3"); + EXPECT_FALSE(cache.Get("b", v)); +}