diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
commit | 19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch) | |
tree | 42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/jaegertracing/thrift/contrib/fb303/TClientInfo.h | |
parent | Initial commit. (diff) | |
download | ceph-upstream.tar.xz ceph-upstream.zip |
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/jaegertracing/thrift/contrib/fb303/TClientInfo.h')
-rw-r--r-- | src/jaegertracing/thrift/contrib/fb303/TClientInfo.h | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/src/jaegertracing/thrift/contrib/fb303/TClientInfo.h b/src/jaegertracing/thrift/contrib/fb303/TClientInfo.h new file mode 100644 index 000000000..6668c1921 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/TClientInfo.h @@ -0,0 +1,320 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 _FACEBOOK_THRIFT_SERVER_TCLIENTINFO_H_ +#define _FACEBOOK_THRIFT_SERVER_TCLIENTINFO_H_ 1 + +// for inet_ntop -- +#include <arpa/inet.h> +#include <thrift/server/TServer.h> +#include <thrift/transport/TSocket.h> +#include <thrift/concurrency/Mutex.h> + +namespace apache { namespace thrift { namespace server { + +using namespace apache::thrift; +using namespace apache::thrift::transport; +using namespace apache::thrift::concurrency; +using boost::shared_ptr; +using std::string; +using std::vector; + +/** + * StableVector -- a minimal vector class where growth is automatic and + * vector elements never move as the vector grows. Allocates new space + * as needed, but does not copy old values. + * + * A level vector stores a list of storage vectors containing the actual + * elements. Levels are added as needed, doubling in size each time. + * Locking is only done when a level is added. Access is amortized + * constant time. + */ +template <typename T> +class StableVector { + /// The initial allocation as an exponent of 2 + static const uint32_t kInitialSizePowOf2 = 10; + /// The initial allocation size + static const uint32_t kInitialVectorSize = 1 << kInitialSizePowOf2; + /// This bound is guaranteed not to be exceeded on 64-bit archs + static const int kMaxLevels = 64; + + /// Values are kept in one or more of these + typedef vector<T> Vect; + /// One or more value vectors are kept in one of these + typedef vector<Vect*> LevelVector; + + Mutex mutex_; + /// current size + size_t size_; + _Atomic_word vectLvl_; + LevelVector vects_; + + public: + /** + * Constructor -- initialize the level vector and allocate the + * initial storage vector + */ + StableVector() + : size_(0) + , vectLvl_(0) { + vects_.reserve(kMaxLevels); + Vect* storageVector(new Vect(1 << kInitialSizePowOf2)); + vects_.push_back(storageVector); + } + + private: + /** + * make sure the requested number of storage levels have been allocated. + */ + void expand(uint32_t level) { + // we need the guard to insure that we only allocate once. + Guard g(mutex_); + while (level > vectLvl_) { + Vect* levelVect(new Vect(1 << (vectLvl_ + kInitialSizePowOf2))); + vects_.push_back(levelVect); + // we need to make sure this is done after levelVect is inserted + // (what we want is effectively a memory barrier here). + __gnu_cxx::__atomic_add(&vectLvl_, 1); + } + } + + /** + * Given an index, determine which level and element of that level is + * required. Grows if needed. + */ + void which(uint32_t n, uint32_t* vno, uint32_t* idx) { + if (n >= size_) { + size_ = n + 1; + } + if (n < kInitialVectorSize) { + *idx = n; + *vno = 0; + } else { + uint32_t upper = n >> kInitialSizePowOf2; + *vno = CHAR_BIT*sizeof(upper) - __builtin_clz(upper); + *idx = n - (1 << (*vno + kInitialSizePowOf2 - 1)); + if (*vno > vectLvl_) { + expand(*vno); + } + } + } + + public: + /** + * Given an index, return a reference to that element, perhaps after + * allocating additional space. + * + * @param n a positive integer + */ + T& operator[](uint32_t n) { + uint32_t vno; + uint32_t idx; + which(n, &vno, &idx); + return (*vects_[vno])[idx]; + } + + /** + * Return the present size of the vector. + */ + size_t size() const { return size_; } +}; + + +/** + * This class embodies the representation of a single connection during + * processing. We'll keep one of these per file descriptor in TClientInfo. + */ +class TClientInfoConnection { + public: + const static int kNameLen = 32; + + private: + typedef union IPAddrUnion { + sockaddr_in ipv4; + sockaddr_in6 ipv6; + }; + + char call_[kNameLen]; ///< The name of the thrift call + IPAddrUnion addr_; ///< The client's IP address + timespec time_; ///< Time processing started + uint64_t ncalls_; ///< # of calls processed + + public: + /** + * Constructor; insure that no client address or thrift call name is + * represented. + */ + TClientInfoConnection(); + + /** + * A connection has been made; record its address. Since this is the + * first we'll know of a connection we start the timer here as well. + */ + void recordAddr(const sockaddr* addr); + + /** + * Mark the address as empty/unknown. + */ + void eraseAddr(); + + /** + * Return a string representing the present address, or NULL if none. + * Copies the string into the buffer provided. + */ + const char* getAddr(char* buf, int len) const; + + /** + * A call has been made on this connection; record its name. Since this is + * called for every thrift call processed, we also do our call count here. + */ + void recordCall(const char* name); + + /** + * Invoked when processing has ended to clear the call name. + */ + void eraseCall(); + + /** + * Return as string the thrift call either currently being processed or + * most recently processed if the connection is still open for additional + * calls. Returns NULL if a call hasn't been made yet or processing + * has ended. + */ + const char* getCall() const; + + /** + * Get the timespec for the start of this connection (specifically, when + * recordAddr() was first called). + */ + void getTime(timespec* time) const; + + /** + * Return the number of calls made on this connection. + */ + uint64_t getNCalls() const; + + private: + void initTime(); +}; + + +/** + * Store for info about a server's clients -- specifically, the client's IP + * address and the call it is executing. This information is indexed by + * socket file descriptor and in the present implementation is updated + * asynchronously, so it may only approximate reality. + */ +class TClientInfo { + private: + StableVector<TClientInfoConnection> info_; + + public: + /** + * Return the info object for a given file descriptor. If "grow" is true + * extend the info vector if required (such as for a file descriptor not seen + * before). If "grow" is false and the info vector isn't large enough, + * or if "fd" is negative, return NULL. + */ + TClientInfoConnection* getConnection(int fd, bool grow); + + size_t size() const; +}; + +/** + * This derivation of TServerEventHandler encapsulates the main status vector + * and provides context to the server's processing loop via overrides. + * Together with TClientInfoCallHandler (derived from TProcessorEventHandler) + * it integrates client info collection into the server. + */ +class TClientInfoServerHandler : public TServerEventHandler { + private: + TClientInfo clientInfo_; + + public: + /** + * One of these is constructed for each open connection/descriptor and links + * to both the status vector (clientInfo_) and that descriptor's entry + * within it. + */ + struct Connect { + TClientInfo* clientInfo_; + TClientInfoConnection* callInfo_; + + explicit Connect(TClientInfo* clientInfo) + : clientInfo_(clientInfo) + , callInfo_(NULL) { + } + }; + + /** + * Generate processor context; we don't know what descriptor we belong to + * yet -- we'll get hooked up in contextProcess(). + */ + void* createContext(boost::shared_ptr<TProtocol> input, + boost::shared_ptr<TProtocol> output); + + /** + * Mark our slot as unused and delete the context created in createContext(). + */ + void deleteContext(void* processorContext, + boost::shared_ptr<TProtocol> input, + boost::shared_ptr<TProtocol> output); + + /** + * Called in the processing loop just before the server invokes the + * processor itself, on the first call we establish which descriptor + * we correspond to and set it to that socket's peer IP address. This + * also has the side effect of initializing call counting and connection + * timing. We won't know which call we're handling until the handler + * first gets called in TClientInfoCallHandler::getContext(). + */ + void processContext(void* processorContext, + shared_ptr<TTransport> transport); + + /** + * Get status report for server in the form of a vector of strings. + * Each active client appears as one string in the format: + * + * FD IPADDR CALLNAME DURATION NCALLS + * + * where "FD" is the file descriptor for the client's socket, "IPADDR" + * is the IP address (as reported by accept()), "CALLNAME" is the + * current or most recent Thrift function name, "DURATION" is the + * duration of the connection, while NCALLS is the number of Thrift + * calls made since the connection was made. A single space separates + * fields. + */ + void getStatsStrings(vector<string>& result); +}; + +/** + * This class derives from TProcessorEventHandler to gain access to the + * function name for the current Thrift call. We need two versions of + * this -- TClientInfoCallStatsHandler is the other -- since in the latter + * case we pass through to TFunctionStatHandler to perform Thrift call + * stats. + */ +class TClientInfoCallHandler : public TProcessorEventHandler { + public: + virtual void* getContext(const char* fn_name, void* serverContext); +}; + +} } } // namespace apache::thrift::server + +#endif // !_FACEBOOK_THRIFT_SERVER_TCLIENTINFO_H_ |