summaryrefslogtreecommitdiffstats
path: root/src/jaegertracing/thrift/contrib/fb303/TClientInfo.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/jaegertracing/thrift/contrib/fb303/TClientInfo.h320
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_