簡體   English   中英

gRPC和etcd客戶端

[英]gRPC and etcd client

這個問題涉及etcd特定的東西,但是我認為這個問題通常與gRPC工作有關。 我正在嘗試為某些鍵創建etcd Watch ,因為文檔稀疏,所以我看了一下諾基亞的實現 。很容易將代碼適應我的需求,我想出了一個效果很好的第一個版本,創建WatchCreateRequest並啟動密鑰更新回調。 到現在為止還挺好。 然后,我嘗試添加多個按鍵來觀看。 慘敗! 在這種情況下, ClientAsyncReaderWriter無法讀取/寫入。 現在到問題。

如果我班上有以下成員

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

並且我想支持添加到我的班級的多個Watches ,我想我必須為每個Watcher保留幾個變量,而不是作為類成員。 首先,我想, WatchResponse reply應該是每個Watch WatchResponse reply 我對信息stream不太確定,是否應該每個Watch保持一個? 我幾乎可以確定context可以被所有Watches重用,並且100%可以確保stubcompletionQueue可以被所有Watches重用。 所以問題是我的猜測正確嗎? 線程安全性如何? 沒有找到任何描述可以從多線程安全使用哪些對象以及必須在哪里同步訪問的文檔。 任何指向文檔的鏈接( 不是此鏈接)將不勝感激!

在將成員分成單個Watch屬性之前測試代碼(我知道沒有適當的關閉)

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;
};

很抱歉,我對此處的Watch設計不太確定。 我不清楚您是否要為每個Watch創建一個gRPC調用。

無論如何,每個gRPC調用都有其自己的ClientContextClientAsyncReaderWriter 但是stubCompletionQueue不是按調用的。

據我所知,沒有中心位置可以找到線程安全類。 您可能需要閱讀API文檔才能獲得正確的期望。

當我編寫異步服務器負載報告服務時 ,我自己添加同步的唯一地方是在CompletionQueue周圍,​​因此,如果關閉了CQ,我就不會將新標簽排隊。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM