13
13
* limitations under the License.
14
14
*/
15
15
#include " src/grpc_transport.h"
16
+
17
+ #include < condition_variable>
16
18
#include < mutex>
19
+ #include < queue>
17
20
#include < thread>
18
21
19
22
namespace istio {
@@ -37,25 +40,26 @@ class GrpcStream final : public WriteInterface<RequestType> {
37
40
38
41
static void Start (
39
42
std::shared_ptr<GrpcStream<RequestType, ResponseType>> grpc_stream) {
40
- std::thread t ([grpc_stream]() { grpc_stream->ReadMainLoop (); });
41
- t.detach ();
43
+ std::thread read_t ([grpc_stream]() { grpc_stream->ReadMainLoop (); });
44
+ read_t .detach ();
45
+ std::thread write_t ([grpc_stream]() { grpc_stream->WriteMainLoop (); });
46
+ write_t .detach ();
42
47
}
43
48
44
49
void Write (const RequestType& request) override {
45
- std::lock_guard<std::mutex> lock (write_mutex_);
46
- if (!stream_->Write (request)) {
47
- GOOGLE_LOG (INFO) << " Stream Write failed: half close" ;
48
- write_closed_ = true ;
49
- }
50
+ // make a copy and push to the queue
51
+ WriteQueuePush (new RequestType (request));
50
52
}
51
53
52
54
void WritesDone () override {
53
- std::lock_guard<std::mutex> lock (write_mutex_);
54
- stream_->WritesDone ();
55
- write_closed_ = true ;
55
+ // push a nullptr to indicate half close
56
+ WriteQueuePush (nullptr );
56
57
}
57
58
58
- bool is_write_closed () const override { return write_closed_; }
59
+ bool is_write_closed () const override {
60
+ std::lock_guard<std::mutex> lock (write_closed_mutex_);
61
+ return write_closed_;
62
+ }
59
63
60
64
private:
61
65
// The worker loop to read response messages.
@@ -67,23 +71,75 @@ class GrpcStream final : public WriteInterface<RequestType> {
67
71
::grpc::Status status = stream_->Finish ();
68
72
GOOGLE_LOG (INFO) << " Stream Finished with status: "
69
73
<< status.error_message ();
74
+
75
+ // Notify Write thread to quit.
76
+ set_write_closed ();
77
+ WriteQueuePush (nullptr );
78
+
70
79
// Convert grpc status to protobuf status.
71
80
::google::protobuf::util::Status pb_status (
72
81
::google::protobuf::util::error::Code (status.error_code()),
73
82
::google::protobuf::StringPiece(status.error_message()));
74
83
reader_->OnClose (pb_status);
75
84
}
76
85
86
+ void WriteQueuePush (RequestType* request) {
87
+ std::unique_lock<std::mutex> lk (write_queue_mutex_);
88
+ write_queue_.emplace (request);
89
+ cv_.notify_one ();
90
+ }
91
+
92
+ std::unique_ptr<RequestType> WriteQueuePop () {
93
+ std::unique_lock<std::mutex> lk (write_queue_mutex_);
94
+ while (write_queue_.empty ()) {
95
+ cv_.wait (lk);
96
+ }
97
+ auto ret = std::move (write_queue_.front ());
98
+ write_queue_.pop ();
99
+ return ret;
100
+ }
101
+
102
+ void set_write_closed () {
103
+ std::lock_guard<std::mutex> lock (write_closed_mutex_);
104
+ write_closed_ = true ;
105
+ }
106
+
107
+ // The worker loop to write request message.
108
+ void WriteMainLoop () {
109
+ while (true ) {
110
+ auto request = WriteQueuePop ();
111
+ if (!request) {
112
+ if (!is_write_closed ()) {
113
+ stream_->WritesDone ();
114
+ set_write_closed ();
115
+ }
116
+ break ;
117
+ }
118
+ if (!stream_->Write (*request)) {
119
+ set_write_closed ();
120
+ break ;
121
+ }
122
+ }
123
+ }
124
+
77
125
// The client context.
78
126
::grpc::ClientContext context_;
79
- // Mutex to make sure not calling stream_->Write() parallelly.
80
- std::mutex write_mutex_;
127
+
81
128
// The reader writer stream.
82
129
StreamPtr stream_;
83
130
// The reader interface from caller.
84
131
ReadInterface<ResponseType>* reader_;
132
+
85
133
// Indicates if write is closed.
134
+ mutable std::mutex write_closed_mutex_;
86
135
bool write_closed_;
136
+
137
+ // Mutex to protect write queue.
138
+ std::mutex write_queue_mutex_;
139
+ // condition to wait for write_queue.
140
+ std::condition_variable cv_;
141
+ // a queue to store pending queue for write
142
+ std::queue<std::unique_ptr<RequestType>> write_queue_;
87
143
};
88
144
89
145
typedef GrpcStream<::istio::mixer::v1::CheckRequest,
0 commit comments