Skip to content

Commit

Permalink
Add attribute context to fill protobuf. (envoyproxy#12)
Browse files Browse the repository at this point in the history
* Add attribute context to fill protobuf.

* Combine dictionary update with attribute filling.

* Add comment
  • Loading branch information
qiwzhang committed Jan 20, 2017
1 parent c02a5f5 commit 1e8b001
Show file tree
Hide file tree
Showing 9 changed files with 348 additions and 54 deletions.
7 changes: 5 additions & 2 deletions mixerclient/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,15 @@ load("@protobuf_git//:protobuf.bzl", "cc_proto_library")
cc_library(
name = "mixer_client_lib",
srcs = [
"src/attribute_context.cc",
"src/attribute_context.h",
"src/attribute_converter.h",
"src/client_impl.cc",
"src/client_impl.h",
"src/stream_transport.h",
"src/signature.cc",
"src/signature.h",
"src/stream_transport.h",
"src/transport.h",
"utils/md5.cc",
"utils/md5.h",
],
Expand Down Expand Up @@ -104,4 +108,3 @@ cc_test(
"//external:googletest_main",
],
)

100 changes: 100 additions & 0 deletions mixerclient/src/attribute_context.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/* 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/attribute_context.h"
#include "google/protobuf/timestamp.pb.h"

using ::google::protobuf::Map;
using ::google::protobuf::Timestamp;

namespace istio {
namespace mixer_client {
namespace {

// TODO: add code to build context to reduce attributes.
// Only check these attributes to build context.
std::set<std::string> kContextSet = {"serviceName", "peerId", "location",
"apiName", "apiVersion"};

// Convert timestamp from time_point to Timestamp
Timestamp CreateTimestamp(std::chrono::system_clock::time_point tp) {
Timestamp time_stamp;
long long nanos = std::chrono::duration_cast<std::chrono::nanoseconds>(
tp.time_since_epoch())
.count();

time_stamp.set_seconds(nanos / 1000000000);
time_stamp.set_nanos(nanos % 1000000000);
return time_stamp;
}

} // namespace

void AttributeContext::FillProto(const Attributes& attributes,
::istio::mixer::v1::Attributes* pb) {
// TODO build context use kContextSet to reduce attributes.

// Fill attributes.
int next_dict_index = dict_map_.size();
bool dict_changed = false;
for (const auto& it : attributes.attributes) {
const std::string& name = it.first;

// Find index for the name.
int index;
const auto& dict_it = dict_map_.find(name);
if (dict_it == dict_map_.end()) {
dict_changed = true;
index = ++next_dict_index;
// Assume attribute names are a fixed name set.
// so not need to remove names from dictionary.
dict_map_[name] = index;
} else {
index = dict_it->second;
}

// Fill the attribute to proper map.
switch (it.second.type) {
case Attributes::Value::ValueType::STRING:
(*pb->mutable_string_attributes())[index] = it.second.str_v;
break;
case Attributes::Value::ValueType::BYTES:
(*pb->mutable_bytes_attributes())[index] = it.second.str_v;
break;
case Attributes::Value::ValueType::INT64:
(*pb->mutable_int64_attributes())[index] = it.second.value.int64_v;
break;
case Attributes::Value::ValueType::DOUBLE:
(*pb->mutable_double_attributes())[index] = it.second.value.double_v;
break;
case Attributes::Value::ValueType::BOOL:
(*pb->mutable_bool_attributes())[index] = it.second.value.bool_v;
break;
case Attributes::Value::ValueType::TIME:
(*pb->mutable_timestamp_attributes())[index] =
CreateTimestamp(it.second.time_v);
break;
}
}

if (dict_changed) {
Map<int32_t, std::string>* dict = pb->mutable_dictionary();
for (const auto& it : dict_map_) {
(*dict)[it.second] = it.first;
}
}
}

} // namespace mixer_client
} // namespace istio
46 changes: 46 additions & 0 deletions mixerclient/src/attribute_context.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* 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.
*/

#ifndef MIXERCLIENT_ATTRIBUTE_CONTEXT_H
#define MIXERCLIENT_ATTRIBUTE_CONTEXT_H

#include "include/client.h"

namespace istio {
namespace mixer_client {

// A class to manage dictionary and context.
class AttributeContext {
public:
AttributeContext() : request_index_(0) {}

// Fill Attributes protobuf.
void FillProto(const Attributes &attributes,
::istio::mixer::v1::Attributes *pb);
// Increments request_index
int64_t IncRequestIndex() { return ++request_index_; }

private:
// dictionary map.
std::map<std::string, int> dict_map_;

// The request_index for this context.
int64_t request_index_;
};

} // namespace mixer_client
} // namespace istio

#endif // MIXERCLIENT_ATTRIBUTE_CONTEXT_H
47 changes: 47 additions & 0 deletions mixerclient/src/attribute_converter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/* 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.
*/

#ifndef MIXERCLIENT_ATTRIBUTE_CONVERTER_H
#define MIXERCLIENT_ATTRIBUTE_CONVERTER_H

#include "include/client.h"

namespace istio {
namespace mixer_client {

// Underlying stream ID.
typedef int64_t StreamID;

// An interface to convert from struct to protobuf.
// It is called by StreamTransport after picking a stream to use.
// It will be implemented by Transport with correct attribute
// context.
template <class RequestType>
class AttributeConverter {
public:
// virtual destructor
virtual ~AttributeConverter() {}

// Convert attributes from struct to protobuf
// It requires an attribute context. A different stream_id
// requires a new attribute context.
virtual void FillProto(StreamID stream_id, const Attributes& attributes,
RequestType* request) = 0;
};

} // namespace mixer_client
} // namespace istio

#endif // MIXERCLIENT_ATTRIBUTE_CONVERTER_H
9 changes: 3 additions & 6 deletions mixerclient/src/client_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,18 @@ MixerClientImpl::MixerClientImpl(const MixerClientOptions &options)
MixerClientImpl::~MixerClientImpl() {}

void MixerClientImpl::Check(const Attributes &attributes, DoneFunc on_done) {
CheckRequest request;
CheckResponse response;
check_transport_.Call(request, &response, on_done);
check_transport_.Send(attributes, &response, on_done);
}

void MixerClientImpl::Report(const Attributes &attributes, DoneFunc on_done) {
ReportRequest request;
ReportResponse response;
report_transport_.Call(request, &response, on_done);
report_transport_.Send(attributes, &response, on_done);
}

void MixerClientImpl::Quota(const Attributes &attributes, DoneFunc on_done) {
QuotaRequest request;
QuotaResponse response;
quota_transport_.Call(request, &response, on_done);
quota_transport_.Send(attributes, &response, on_done);
}

// Creates a MixerClient object.
Expand Down
12 changes: 5 additions & 7 deletions mixerclient/src/client_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#define MIXERCLIENT_CLIENT_IMPL_H

#include "include/client.h"
#include "src/stream_transport.h"
#include "src/transport.h"

namespace istio {
namespace mixer_client {
Expand All @@ -36,14 +36,12 @@ class MixerClientImpl : public MixerClient {

private:
MixerClientOptions options_;
StreamTransport<::istio::mixer::v1::CheckRequest,
::istio::mixer::v1::CheckResponse>
Transport<::istio::mixer::v1::CheckRequest, ::istio::mixer::v1::CheckResponse>
check_transport_;
StreamTransport<::istio::mixer::v1::ReportRequest,
::istio::mixer::v1::ReportResponse>
Transport<::istio::mixer::v1::ReportRequest,
::istio::mixer::v1::ReportResponse>
report_transport_;
StreamTransport<::istio::mixer::v1::QuotaRequest,
::istio::mixer::v1::QuotaResponse>
Transport<::istio::mixer::v1::QuotaRequest, ::istio::mixer::v1::QuotaResponse>
quota_transport_;

GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MixerClientImpl);
Expand Down
17 changes: 14 additions & 3 deletions mixerclient/src/stream_transport.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#define MIXERCLIENT_STREAM_TRANSPORT_H

#include "include/client.h"
#include "src/attribute_converter.h"

namespace istio {
namespace mixer_client {
Expand Down Expand Up @@ -89,11 +90,15 @@ class ReaderImpl : public ReadInterface<ResponseType> {
template <class RequestType, class ResponseType>
class StreamTransport {
public:
StreamTransport(TransportInterface* transport)
: transport_(transport), reader_(nullptr), writer_(nullptr) {}
StreamTransport(TransportInterface* transport,
AttributeConverter<RequestType>* converter)
: transport_(transport),
converter_(converter),
reader_(nullptr),
writer_(nullptr) {}

// Make a ping-pong call.
void Call(const RequestType& request, ResponseType* response,
void Call(const Attributes& attributes, ResponseType* response,
DoneFunc on_done) {
if (transport_ == nullptr) {
on_done(::google::protobuf::util::Status(
Expand All @@ -119,13 +124,19 @@ class StreamTransport {
delete writer;
});
}
RequestType request;
// Cast the writer_ raw pointer as StreamID.
converter_->FillProto(reinterpret_cast<StreamID>(writer_), attributes,
&request);
reader_->AddRequest(request.request_index(), response, on_done);
writer_->Write(request);
}

private:
// The transport interface to create a new stream.
TransportInterface* transport_;
// Attribute converter.
AttributeConverter<RequestType>* converter_;
// The reader object for current stream.
ReaderImpl<ResponseType>* reader_;
// The writer object for current stream.
Expand Down
Loading

0 comments on commit 1e8b001

Please sign in to comment.