代码之家  ›  专栏  ›  技术社区  ›  kreuzerkrieg

gRPC和etcd客户端

  •  0
  • kreuzerkrieg  · 技术社区  · 8 年前

    这个问题涉及 etcd 具体的问题,但我认为这个问题与 gRPC 一般来说。 我在努力创造 etcd公司 Watch 对于一些键,由于文档很少,我看了一下诺基亚 implementation 很容易使代码适应我的需要,我想出了第一个版本,它工作得很好,创建了 WatchCreateRequest ,并在密钥更新时启动回调到现在为止,一直都还不错。然后我试着加了不止一把钥匙看。惨败! ClientAsyncReaderWriter 在这种情况下无法读/写。现在来回答这个问题。

    如果我班上有下列成员

    Watch::Stub watchStub;
    CompletionQueue completionQueue;
    ClientContext context;
    std::unique_ptr<ClientAsyncReaderWriter<WatchRequest, WatchResponse>> stream;
    WatchResponse reply;
    

    我想支持多个 Watches 加上我的类,我想我必须持有几个变量每手表,而不是作为类成员。 首先,我想, WatchResponse reply 应该是每个 手表 是的。我不太确定 stream ,我应该每人拿一个吗 手表 ? 我几乎可以肯定 context 可以重复使用 手表 100%确定 stub completionQueue 可重复使用 手表 是的。 所以问题是我的猜测正确吗?什么是线程安全?没有找到任何文档描述从多线程使用哪些对象是安全的,以及我必须在何处同步访问。 任何文档链接( not this one )将不胜感激!

    在将成员拆分为单个成员之前测试代码 监视 财产 (我知道,没有正常关机)

    using namespace grpc;
    class Watcher
    {
    public:
        using Callback = std::function<void(const std::string&, const std::string&)>;
    
        Watcher(std::shared_ptr<Channel> channel) : watchStub(channel)
        {
            stream = watchStub.AsyncWatch(&context, &completionQueue, (void*) "create");
            eventPoller = std::thread([this]() { WaitForEvent(); });
        }
    
        void AddWatch(const std::string& key, Callback callback)
        {
            AddWatch(key, callback, false);
        }
    
        void AddWatches(const std::string& key, Callback callback)
        {
            AddWatch(key, callback, true);
        }
    
    private:
        void AddWatch(const std::string& key, Callback callback, bool isRecursive)
        {
            auto insertionResult = callbacks.emplace(key, callback);
            if (!insertionResult.second) {
                throw std::runtime_error("Event handle already exist.");
            }
            WatchRequest watch_req;
            WatchCreateRequest watch_create_req;
            watch_create_req.set_key(key);
            if (isRecursive) {
                watch_create_req.set_range_end(key + "\xFF");
            }
    
            watch_req.mutable_create_request()->CopyFrom(watch_create_req);
            stream->Write(watch_req, (void*) insertionResult.first->first.c_str());
    
            stream->Read(&reply, (void*) insertionResult.first->first.c_str());
        }
    
        void WaitForEvent()
        {
            void* got_tag;
            bool ok = false;
    
            while (completionQueue.Next(&got_tag, &ok)) {
                if (ok == false) {
                    break;
                }
                if (got_tag == (void*) "writes done") {
                    // Signal shutdown
                }
                else if (got_tag == (void*) "create") {
                }
                else if (got_tag == (void*) "write") {
                }
                else {
    
                    auto tag = std::string(reinterpret_cast<char*>(got_tag));
                    auto findIt = callbacks.find(tag);
                    if (findIt == callbacks.end()) {
                        throw std::runtime_error("Key \"" + tag + "\"not found");
                    }
    
                    if (reply.events_size()) {
                        ParseResponse(findIt->second);
                    }
                    stream->Read(&reply, got_tag);
                }
            }
        }
    
        void ParseResponse(Callback& callback)
        {
            for (int i = 0; i < reply.events_size(); ++i) {
                auto event = reply.events(i);
                auto key = event.kv().key();
                callback(event.kv().key(), event.kv().value());
            }
        }
    
        Watch::Stub watchStub;
        CompletionQueue completionQueue;
        ClientContext context;
        std::unique_ptr<ClientAsyncReaderWriter<WatchRequest, WatchResponse>> stream;
        WatchResponse reply;
        std::unordered_map<std::string, Callback> callbacks;
        std::thread eventPoller;
    };
    
    1 回复  |  直到 8 年前
        1
  •  1
  •   Juanli Shen    8 年前

    很抱歉我不太确定 Watch 在这里设计。我不太清楚你是否想为每个 手表 是的。

    不管怎样,每个gRPC呼叫都有自己的 ClientContext , ClientAsyncReaderWriter 是的。但是 stub CompletionQueue 不是每次通话的事。

    据我所知,没有找到线程安全类的中心位置您可能希望阅读api文档以获得正确的预期。

    当我在写 async server load reporting service ,我自己添加同步的唯一地方是 完成队列 ,以便在cq关闭时,我不会将新标记排队到cq。