The function tier
The function tier represents the initial ingress layer of our sample
application. Its job is to receive requests via Google’s gRPC
protocol, to select a backend node to handle the request, and to
forward that request along via Derecho’s p2p_send
. Let’s take a look at the header:
#pragma once
#include <derecho/core/derecho.hpp>
#include <derecho/mutils-serialization/SerializationSupport.hpp>
#include <function_tier.grpc.pb.h>
#include <grpcpp/grpcpp.h>
#include <memory>
#include <mutex>
namespace sospdemo {
#define FUNCTION_TIER_GRPC_PORT_BASE (28000)
class FunctionTier : public mutils::ByteRepresentable,
public derecho::GroupReference,
public FunctionTierService::Service {
protected:
std::map<uint64_t, ssize_t> tag_to_shard;
std::atomic<bool> started;
std::mutex service_mutex;
std::unique_ptr<grpc::Server> server;
virtual grpc::Status Whatsthis(grpc::ServerContext* context,
grpc::ServerReader<PhotoRequest>* reader,
PhotoReply* reply) override;
virtual grpc::Status InstallModel(grpc::ServerContext* context,
grpc::ServerReader<InstallModelRequest>* reader,
ModelReply* reply) override;
virtual grpc::Status RemoveModel(grpc::ServerContext* context,
const RemoveModelRequest* request,
ModelReply* reply) override;
virtual void start();
virtual void shutdown();
public:
FunctionTier() {
started = false;
start();
}
FunctionTier(std::map<uint64_t, ssize_t>& rhs) {
this->tag_to_shard = std::move(rhs);
started = false;
start();
}
virtual ~FunctionTier();
static auto register_functions() { return std::tuple<>(); };
DEFAULT_SERIALIZATION_SUPPORT(FunctionTier, tag_to_shard);
};
}
Much of this code is required to implement the gRPC layer. We’ll highlight those as needed, but mostly focus on the Derecho components of this class.
Includes and superclasses
#include <derecho/core/derecho.hpp>
#include <derecho/mutils-serialization/SerializationSupport.hpp>
#include <function_tier.grpc.pb.h>
#include <grpcpp/grpcpp.h>
#include <memory>
#include <mutex>
The thing to notice here is that, beyond including the
derecho/core/derecho.hpp
header included by most Derecho-using
components, we’re also including the SerializatonSupport.hpp
header.
This is a lightweight serialization framework which provides macros
via which one can generate serialization and deserialization code.
We’re also including two libraries (function_tier.grpc.pb.h
,
grpcpp/grpcpp.h
) to support gRPC, and some standard C++ libraries.
More interesting is the superclasses extended by our function tier:
class FunctionTier : public mutils::ByteRepresentable,
public derecho::GroupReference,
public FunctionTierService::Service
The ByteRepresentable
class works with SerializationSupport
to
mark this class as serializable.
The GroupReference
class, taking inspiration from the
std::enable_shared_from_this
, will provide a member pointer called
group
which can be used within the FunctionTier
to access the
group to which this FunctionTier
instance belongs.
The FunctionTierService::Service
class is generated by gRPC, and
provides entry points for receiving gRPC messages.
gRPC entry points
virtual grpc::Status Whatsthis(grpc::ServerContext* context,
grpc::ServerReader<PhotoRequest>* reader,
PhotoReply* reply) override;
virtual grpc::Status InstallModel(grpc::ServerContext* context,
grpc::ServerReader<InstallModelRequest>* reader,
ModelReply* reply) override;
virtual grpc::Status RemoveModel(grpc::ServerContext* context,
const RemoveModelRequest* request,
ModelReply* reply) override;
These method signatures are generated by gRPC to receive requests as
defined by our protocol files. These requests will then be forwarded
on to the categorizer tier via Derecho. The Whatsthis
request
receives a photo to identify and a list of previously-installed image
models to use when recognizing the photo. The InstallModel
request
installs a new model for use when recognizing images. The
RemoveModel
request removes a previously-installed model.
Derecho Registration
Way down at the bottom of the class, we have two lines which are required for Derecho:
static auto register_functions() { return std::tuple<>(); };
DEFAULT_SERIALIZATION_SUPPORT(FunctionTier, tag_to_shard);
The first line (register_functions
) specifies which methods for this
class should be invokable via p2p_send
or ordered_send
. Since
this class does not receive unsolicited messages from within Derecho,
we don’t have to register any particular functions as Derecho RPC
targets.
The second line tells the serialization framework which fields of this
class should be serialized as part of this class. In this case, we’re
only serializing the map tag_to_shard
; we leave off the other
fields, as we don’t want to try and send an atomic boolean or mutex
over the network!
The parts of this class which we didn’t highlight are largely straightforward, or boilerplate required by the gRPC layer.