Skip to content

Commit

Permalink
Support attribute context update. (envoyproxy#31)
Browse files Browse the repository at this point in the history
* Support attribute context update.

* Not to set attribute_context.

* Fix format.
  • Loading branch information
qiwzhang committed Mar 3, 2017
1 parent 9a09457 commit ed4b3d4
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 83 deletions.
4 changes: 3 additions & 1 deletion mixerclient/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ load("@protobuf_git//:protobuf.bzl", "cc_proto_library")
cc_library(
name = "mixer_client_lib",
srcs = [
"src/attribute.cc",
"src/attribute_context.cc",
"src/attribute_context.h",
"src/attribute_converter.h",
Expand All @@ -37,15 +38,16 @@ cc_library(
"utils/status_test_util.h",
],
hdrs = [
"include/attribute.h",
"include/client.h",
"include/options.h",
"include/transport.h",
],
visibility = ["//visibility:public"],
deps = [
":simple_lru_cache",
"//external:grpc++",
"//external:boringssl_crypto",
"//external:grpc++",
"//external:mixer_api_cc_proto",
],
)
Expand Down
71 changes: 71 additions & 0 deletions mixerclient/include/attribute.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/* 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_H
#define MIXERCLIENT_ATTRIBUTE_H

#include <chrono>
#include <functional>
#include <map>
#include <memory>
#include <string>

namespace istio {
namespace mixer_client {

// A structure to represent a bag of attributes with
// different types.
struct Attributes {
// A structure to hold different types of value.
struct Value {
// Data type
enum ValueType {
STRING,
INT64,
DOUBLE,
BOOL,
TIME,
BYTES,
DURATION,
STRING_MAP
} type;

// Data value
union {
int64_t int64_v;
double double_v;
bool bool_v;
} value;
// Move types with constructor outside of union.
// It is not easy for union to support them.
std::string str_v; // for both STRING and BYTES
std::chrono::time_point<std::chrono::system_clock> time_v;
std::chrono::nanoseconds duration_nanos_v;
std::map<std::string, std::string> string_map_v;

// compare operator
bool operator==(const Value& v) const;
};

std::map<std::string, Value> attributes;

// Generates a string for logging or debugging.
std::string DebugString() const;
};

} // namespace mixer_client
} // namespace istio

#endif // MIXERCLIENT_ATTRIBUTE_H
41 changes: 1 addition & 40 deletions mixerclient/include/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,7 @@
#ifndef MIXERCLIENT_CLIENT_H
#define MIXERCLIENT_CLIENT_H

#include <chrono>
#include <functional>
#include <memory>
#include <string>

#include "attribute.h"
#include "google/protobuf/stubs/status.h"
#include "options.h"
#include "transport.h"
Expand Down Expand Up @@ -62,41 +58,6 @@ struct MixerClientOptions {
TransportInterface* transport;
};

struct Attributes {
// A structure to hold different types of value.
struct Value {
// Data type
enum ValueType {
STRING,
INT64,
DOUBLE,
BOOL,
TIME,
BYTES,
DURATION,
STRING_MAP
} type;

// Data value
union {
int64_t int64_v;
double double_v;
bool bool_v;
} value;
// Move types with constructor outside of union.
// It is not easy for union to support them.
std::string str_v; // for both STRING and BYTES
std::chrono::time_point<std::chrono::system_clock> time_v;
std::chrono::nanoseconds duration_nanos_v;
std::map<std::string, std::string> string_map_v;
};

std::map<std::string, Value> attributes;

// Generates a string for logging or debugging.
std::string DebugString() const;
};

class MixerClient {
public:
// Destructor
Expand Down
96 changes: 96 additions & 0 deletions mixerclient/src/attribute.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/* 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 "include/attribute.h"
#include <sstream>

namespace istio {
namespace mixer_client {

bool Attributes::Value::operator==(const Attributes::Value &v) const {
if (type != v.type) {
return false;
}
switch (type) {
case Attributes::Value::ValueType::STRING:
case Attributes::Value::ValueType::BYTES:
return str_v == v.str_v;
break;
case Attributes::Value::ValueType::INT64:
return value.int64_v == v.value.int64_v;
break;
case Attributes::Value::ValueType::DOUBLE:
return value.double_v == v.value.double_v;
break;
case Attributes::Value::ValueType::BOOL:
return value.bool_v == v.value.bool_v;
break;
case Attributes::Value::ValueType::TIME:
return time_v == v.time_v;
break;
case Attributes::Value::ValueType::DURATION:
return duration_nanos_v == v.duration_nanos_v;
break;
case Attributes::Value::ValueType::STRING_MAP:
return string_map_v == v.string_map_v;
break;
}
return false;
}

std::string Attributes::DebugString() const {
std::stringstream ss;
for (const auto &it : attributes) {
ss << it.first << ": ";
switch (it.second.type) {
case Attributes::Value::ValueType::STRING:
ss << "(STRING): " << it.second.str_v;
break;
case Attributes::Value::ValueType::BYTES:
ss << "(BYTES): " << it.second.str_v;
break;
case Attributes::Value::ValueType::INT64:
ss << "(INT64): " << it.second.value.int64_v;
break;
case Attributes::Value::ValueType::DOUBLE:
ss << "(DOUBLE): " << it.second.value.double_v;
break;
case Attributes::Value::ValueType::BOOL:
ss << "(BOOL): " << it.second.value.bool_v;
break;
case Attributes::Value::ValueType::TIME:
ss << "(TIME ms): "
<< std::chrono::duration_cast<std::chrono::microseconds>(
it.second.time_v.time_since_epoch())
.count();
break;
case Attributes::Value::ValueType::DURATION:
ss << "(DURATION nanos): " << it.second.duration_nanos_v.count();
break;
case Attributes::Value::ValueType::STRING_MAP:
ss << "(STRING MAP):";
for (const auto &map_it : it.second.string_map_v) {
ss << std::endl;
ss << " " << map_it.first << ": " << map_it.second;
}
break;
}
ss << std::endl;
}
return ss.str();
}

} // namespace mixer_client
} // namespace istio
37 changes: 37 additions & 0 deletions mixerclient/src/attribute_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,30 @@ Duration CreateDuration(std::chrono::nanoseconds value) {

} // namespace

void AttributeContext::Context::UpdateStart() {
curr_set_.clear();
for (const auto& it : map_) {
curr_set_.insert(it.first);
}
}

bool AttributeContext::Context::Update(int index, Attributes::Value value) {
auto it = map_.find(index);
bool same = (it != map_.end() && it->second == value);
if (!same) {
map_[index] = value;
}
curr_set_.erase(index);
return same;
}

std::set<int> AttributeContext::Context::UpdateFinish() {
for (const auto it : curr_set_) {
map_.erase(it);
}
return curr_set_;
}

int AttributeContext::GetNameIndex(const std::string& name) {
const auto& dict_it = dict_map_.find(name);
int index;
Expand Down Expand Up @@ -79,11 +103,19 @@ void AttributeContext::FillProto(const Attributes& attributes,

size_t old_dict_size = dict_map_.size();

context_.UpdateStart();

// Fill attributes.
for (const auto& it : attributes.attributes) {
const std::string& name = it.first;

int index = GetNameIndex(name);

// Check the context, if same, no need to send it.
if (context_.Update(index, it.second)) {
continue;
}

// Fill the attribute to proper map.
switch (it.second.type) {
case Attributes::Value::ValueType::STRING:
Expand Down Expand Up @@ -116,6 +148,11 @@ void AttributeContext::FillProto(const Attributes& attributes,
}
}

auto deleted_attrs = context_.UpdateFinish();
for (const auto& it : deleted_attrs) {
pb->add_deleted_attributes(it);
}

// Send the dictionary if it is changed.
if (old_dict_size != dict_map_.size()) {
Map<int32_t, std::string>* dict = pb->mutable_dictionary();
Expand Down
25 changes: 25 additions & 0 deletions mixerclient/src/attribute_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,28 @@ class AttributeContext {
int64_t IncRequestIndex() { return ++request_index_; }

private:
// A class to keep track of current request context.
class Context {
public:
// Start a update for a request.
void UpdateStart();

// Check an attribute, return true if the attribute
// is in the context with same value, not need to send it.
// Otherwise, update the context.
bool Update(int index, Attributes::Value value);

// Finish a update for a request, remove these not in
// the current request, and return the deleted set.
std::set<int> UpdateFinish();

private:
// The remaining attribute set in a request.
std::set<int> curr_set_;
// The attribute map in the context.
std::map<int, Attributes::Value> map_;
};

// Find the index for a name. If not found, create a new one.
int GetNameIndex(const std::string& name);

Expand All @@ -45,6 +67,9 @@ class AttributeContext {

// The request_index for this context.
int64_t request_index_;

// The attribute context.
Context context_;
};

} // namespace mixer_client
Expand Down
42 changes: 0 additions & 42 deletions mixerclient/src/client_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -89,47 +89,5 @@ std::unique_ptr<MixerClient> CreateMixerClient(
return std::unique_ptr<MixerClient>(new MixerClientImpl(options));
}

std::string Attributes::DebugString() const {
std::stringstream ss;
for (const auto &it : attributes) {
ss << it.first << ": ";
switch (it.second.type) {
case Attributes::Value::ValueType::STRING:
ss << "(STRING): " << it.second.str_v;
break;
case Attributes::Value::ValueType::BYTES:
ss << "(BYTES): " << it.second.str_v;
break;
case Attributes::Value::ValueType::INT64:
ss << "(INT64): " << it.second.value.int64_v;
break;
case Attributes::Value::ValueType::DOUBLE:
ss << "(DOUBLE): " << it.second.value.double_v;
break;
case Attributes::Value::ValueType::BOOL:
ss << "(BOOL): " << it.second.value.bool_v;
break;
case Attributes::Value::ValueType::TIME:
ss << "(TIME ms): "
<< std::chrono::duration_cast<std::chrono::microseconds>(
it.second.time_v.time_since_epoch())
.count();
break;
case Attributes::Value::ValueType::DURATION:
ss << "(DURATION nanos): " << it.second.duration_nanos_v.count();
break;
case Attributes::Value::ValueType::STRING_MAP:
ss << "(STRING MAP):";
for (const auto &map_it : it.second.string_map_v) {
ss << std::endl;
ss << " " << map_it.first << ": " << map_it.second;
}
break;
}
ss << std::endl;
}
return ss.str();
}

} // namespace mixer_client
} // namespace istio

0 comments on commit ed4b3d4

Please sign in to comment.