Basic components of microservice open source framework tars

Time:2020-9-25

Basic components of microservice open source framework tars

author herman

Introduction

This paper is based on one of Herman’s series of articles, “basic components of goose factory open source framework tars”. The relevant code has been updated according to the latest version of tars open source community.

In the tars open source framework library, C + + is used to implement more common components, which are generally placed in theutilThe folder can also be used freely in the application layer. If a worker wants to do a good job, he must first use his tools. Therefore, it is necessary to understand these tool components, use them better and improve efficiency. Next, this paper will analyze the tarscpp components as follows:

  • Thread operation

    • Thread safe queue: TC_ ThreadQueue
    • Common thread lock: TC_ ThreadLock
    • Thread base class: TC_ Thread
  • Smart pointer

    • Smart pointer class: TC_ AutoPtr
  • DB operation

    • MySQL operation class: TC_ Mysql
  • Network operation

    • Network components
  • Service configuration

    • Command parsing class: TC_ Option
    • Profile class: TC_ Config
  • functor

    • Generic functor class: TC_ Functor
  • Hash

    • Hash algorithm
  • exception handling

    • Exception class: TC_ Exception

Thread safe queue: TC_ ThreadQueue

Let’s take a look at the frame first. YesTC_ThreadQueueClass is used as follows:

typedef TC_ ThreadQueue<tagRecvData*, deque<tagRecvData*> > recv_ Queue; // receive queue
typedef TC_ ThreadQueue<tagSendData*, deque<tagSendData*> > send_ Queue; // send queue

TC_ThreadQueueThis class is more important in the network layer implementation of tars, because the network packets received from the framework will be added to the cache queue, and then multi service threads will be generatedServantHandleWill callwaitForRecvQueueTake the network packet from the queue and call it.dispatchCall the processing function corresponding to the protocol message. First, let’s take a look at the framework pairTC_ThreadQueueImplementation of:

/**
 *@ brief thread safe queue
 */
template<typename T, typename D = deque<T> >
class TC_ThreadQueue
{
public:
    TC_ThreadQueue():_size(0){};

public:

    typedef D queue_type;

    /**
     *@ brief gets data from the header, no data throw exception
     *
     * @param t
     *@ return bool: true, obtained data, false, no data
     */
    T front();

    /**
     *@ brief gets data from the header. If there is no data, wait
     *
     * @param t 
     *@ param milsecond (valid when wait = true) blocking waiting time (MS)
     *0 means no blocking 
     *- 1 permanent waiting
     *@ param wait, wait
     *@ return bool: true, obtained data, false, no data
     */
    bool pop_front(T& t, size_t millsecond = 0, bool wait = true);
    ...
    ...
}

TC_ThreadQueueThe c++11 standard library is used<mutex>and<condition_variable>It is used to implement thread lock and wait, as shown in the following figurepush_frontAdd data in front of the queue,

template<typename T, typename D> void TC_ThreadQueue<T, D>::push_front(const T& t, bool notify)
{
    if(notify) {
        std::unique_lock<std::mutex> lock(_mutex);

        _cond.notify_one();

        _queue.push_front(t);

        ++_size;
    }
    else
    {
        std::lock_guard<std::mutex> lock (_mutex);

        _queue.push_front(t);

        ++_size;
    }
}

Call it as shown in the figure abovepush_frontFunctionstd::unique_lock<std::mutex> lock(_mutex)Lock to avoid data conflict between network layer receiving data and service layer accessing the same queue,_cond.notify_one()Notice to wait for a thread to wake up on the lock, and lock it before calling the function, because there is data coming. For example, there are threads in the network layer that need to fetch packets and distribute them.

Let’s look at a member functionpop_front, get data from the header, wait if there is no data.millisecondBlocking waiting time (MS)

  • 0No blocking
  • -1Waiting forever
template<typename T, typename D> bool TC_ThreadQueue<T, D>::pop_front(T& t, size_t millsecond, bool wait)
{
    if(wait) {

        std::unique_lock<std::mutex> lock(_mutex);

        if (_queue.empty()) {
            if (millsecond == 0) {
                return false;
            }
            if (millsecond == (size_t) -1) {
                _cond.wait(lock);
            }
            else {
                //Time out
                if (_cond.wait_for(lock, std::chrono::milliseconds(millsecond)) == std::cv_status::timeout) {
                    return false;
                }
            }
        }

        if (_queue.empty()) {
            return false;
        }

        t = _queue.front();
        _queue.pop_front();
        assert(_size > 0);
        --_size;

        return true;
    }
    else
    {
        std::lock_guard<std::mutex> lock (_mutex);
        if (_queue.empty())
        {
            return false;
        }

        t = _queue.front();
        _queue.pop_front();
        assert(_size > 0);
        --_size;

        return true;
    }
}

BindAdapter::waitForRecvQueueIs calledpop_frontFunction, which is used to wait for the receiving queue. The function prototype is as follows:

bool TC_EpollServer::BindAdapter::waitForRecvQueue(uint32_t handleIndex, shared_ptr<RecvContext> &data)
{
    bool bRet = getRecvQueue(handleIndex).pop_front(data);

    if (!bRet)
    {
        return bRet;
    }

    --_iRecvBufferSize;

    return bRet;
}

hereBindAdapter::waitForRecvQueueIt is used for business threads to process service packets after the adapter waiting for the server to listen receives network packetshandleIndexRepresents the receive queue index and gets the corresponding_rbuffer

Common thread lock: TC_ ThreadLock

TC_ThreadLockClass is defined as follows

typedef TC_Monitor<TC_ThreadMutex, TC_ThreadCond> TC_ThreadLock;

TC_MonitorThread lock monitoring template class. Usually, thread locks are used through this class, not directlyTC_ThreadMutexTC_ThreadRecMutex

Definition of classtemplate <class T, class P> class TC_MonitorYou need to pass in two template parameters,TC_MonitorIncludes the following member variables:

mutable int     _ Nnotify; // number of locks
mutable P       _ Cond; // condition variable
T               _ Mutex; // mutex
/**
 *@ brief defines the lock control object
 */
typedef TC_LockT<TC_Monitor<T, P> > Lock;
typedef TC_TryLockT<TC_Monitor<T, P> > TryLock;

First parameterTC_ThreadMutexRepresents thread lock: the same thread cannot be locked repeatedly, including member variables

mutable std::mutex _mutex

Extended reading, heretc_thread_mutex.hThere is also another circular lock classTC_ThreadRecMutexIn other words, a thread can be locked multiple times, which is defined as follows:

//Defined in TC_ Monitor. H
typedef TC_Monitor<TC_ThreadRecMutex, TC_ThreadCond> TC_ThreadRecLock;

Second parameterTC_ThreadCondRepresents the thread signal condition class: all locks can wait for the signal to occur, including the thread condition member variable:

mutable std::condition_variable_any _cond

Combined with the actual use scenarios,TC_Monitor::timedWait()Will callTC_ThreadCondObject’stimedWaitFunction, next callchronoLibrary’smillisecondsTC_ThreadCond::signal()The implementation sends a signal and a thread waiting on the condition will wake up.

TC_LockTClass definition:template <typename T> class TC_LockTLock template class, used in conjunction with other specific locks, locks are added during construction and unlocked when analyzed.

TC_LockTConstructor, passing in the mutex to initialize the member variable_mutexTC_LockTConstructor implementation:

TC_LockT(const T& mutex) : _mutex(mutex) {
        _mutex.lock();
        _acquired = true;
}

You can see it hereTC_MonitorDefinedtypedef TC_LockT<TC_Monitor<T, P> > LockHereLockThe template parameters of type areTC_MonitorClass.

The actual application scenarios are as follows:

Lock lock(*this);

TC_LockTThe constructor of, passing in the parameterthisbyTC_MonitorSubclass object of,TC_LockTConstructor call for_mutex.lock(); it’s calledTC_MonitorObject’slockFunction,TC_MonitorOflockFunction implementation:

void lock() const
{
    _mutex.lock();
    _nnotify = 0;
}

here_mutexbyTC_ThreadMutexObject, further calling theTC_ThreadRecMutex::lock()Member functions are implemented as follows:

void TC_ThreadMutex::lock() const
{
    _mutex.lock();
}

It is called when the lock stack variable defined above exits the functionTC_LockTThe destructor is implemented as follows:

virtual ~TC_LockT()
{
    if (_acquired)
    {
        A kind of mutex.unlock (); // TC is called here_ Monitor's unlock function
    }
}

TC_MonitorOfunlockFunction implementation:

void unlock() const
{
    notifyImpl(_nnotify);
    A kind of mutex.unlock (); // the unlock in the C + + standard library < mutex > will be called here
}

Call herenotifyImplFunction is becauseTC_MonitorClass can not only implement simple mutex lock function, but also implement condition function, wherenotifyImplThe implementation of

void notifyImpl(int nnotify) const
{
    if(nnotify != 0)
    {
        if(nnotify == -1)
        {
            _cond.broadcast();
            return;
        }
        else
        {
            while(nnotify > 0)
            {
                _cond.signal();
                --nnotify;
            }
        }
    }
}

Thread base class: TC_ Thread

As usual, let’s take a look at the actual use of thread base classes in the project. In the actual project use, weTC_ThreadIt’s encapsulated again and implemented aBasicThreadClass, let’s take a lookBasicThreadDefinition of:

class BasicThread : public tars::TC_Thread, public tars::TC_ThreadLock
{

   ...

    void terminate()
    {
        _bTerm = true;
        {
            Lock lock(*this);
            notifyAll();
        }
        getThreadControl().join();
    }
}

BasicThreadClass, inheritingTC_ThreadandTC_ThreadLockIn whichTC_ThreadLockThe second point has been explained, so let’s focus on itTC_ThreadClass,TC_ThreadDefinition of

class TC_Thread : public TC_Runable
{

    ...
    
    /**
     *Using the C + + 11 standard thread library STD:: thread, the constructor passes the parameter threadentry thread function,
     *Return to TC_ ThreadControl(_ Th), where_ Th is the STD:: thread object
     */
    TC_ThreadControl start();

    static void threadEntry(TC_ Thread * pthread); // static function, thread entry

    virtual void run() = 0;

    ...
}

Next, look at the thread control classTC_ThreadControlDefinition of:

class TC_ThreadControl 
{
...
explicit TC_ Threadcontrol (STD:: thread * th); // construct, pass in the STD:: thread object

Void join(); // call the join() of STD:: thread to block the current thread until another thread finishes running

Static void sleep(); // call STD:: this_ Thread:: sleep function thread will pause execution
...
}

Take a look at the next stepTC_RunableDefinition of:

class TC_Runable
{
public:
    virtual ~TC_Runable(){};
    Virtual void run() = 0; // defines the run pure virtual function
};

Finally, take a look at the use of thread classes in the actual project

Class antisdksyncthread: public basicthread // here, it means that many TC are inherited_ Thread and TC_ Two classes of threadlock
{
    Void run() // implement pure virtual function of base class
    {
        Lock lock(*this);

        Timedwait (10 * 1000); (interval execution time, realizing the function of thread timing execution)

            if(NULL != g_busi_interf)
            {
                Int32 ret = g_ busi_ interf->proc_ (); // functions that need to be executed periodically
            }
    }
}

It’s definedAntiSdkSyncThread g_antiSdkSyncThread;Class, it is executed when the thread needs to be startedg_antiSdkSyncThread.start();The thread will be created naturally, andthreadEntryThe thread function calls thepThread->run()Polymorphic function, called when the process exitsg_antiSdkSyncThread.terminate();

Smart pointer class: TC_ AutoPtr

The smart pointer here can be placed in the container, and the thread safe smart pointer is of cpp11 standard libraryauto_ptrIt can’t be put in the container. It seems to have been eliminated. At present, most of them use cpp11 standard libraryshared_ptr, but requires the compiler to support cpp11.

TC_HandleBaseThe definition of smart pointer base class is as follows. All classes that need smart pointer need to inherit from this object, which uses the<atomic>Count the atoms.

class UTIL_DLL_API TC_HandleBase
{
public:

    /**
     *@ brief copy
     *
     * @return TC_HandleBase&
     */
    TC_HandleBase& operator=(const TC_HandleBase&)
    {
        return *this;
    }

    /**
     *@ brief increase count
     */
    void incRef() { ++_atomic; }

    /**
     *@ brief reduce count
     */
    void decRef()
    {
        if((--_atomic) == 0 && !_bNoDelete)
        {
            _bNoDelete = true;
            delete this;
        }
    }

    /**
     *@ brief gets the count
     *
     *@ return int count
     */
    int getRef() const        { return _atomic; }

    /**
     *The @ brief setting is not released automatically 
     *  
     *Is @ param B automatically deleted, true or false
     */
    void setNoDelete(bool b)  { _bNoDelete = b; }

protected:

    /**
     *@ brief constructor    
     */
    TC_HandleBase() : _atomic(0), _bNoDelete(false)
    {
    }

    /**
     *@ brief copy structure
     */
    TC_HandleBase(const TC_HandleBase&) : _atomic(0), _bNoDelete(false)
    {
    }

    /**
     *@ brief deconstruction
     */
    virtual ~TC_HandleBase()
    {
    }

protected:

    std::atomic<int>    _ Atomic; // reference count
    bool                _ Bnodelete; // delete automatically
};

Look at it nextTC_AutoPtrThe smart pointer template class is a thread safe smart pointer that can be placed in a container. The smart pointer is implemented by reference counting. Its constructor and destructor are defined as follows:

template<typename T> 
class TC_AutoPtr
{ 
    TC_AutoPtr(T* p = 0)
    {
        _ptr = p;

        if(_ptr)
        {
            A kind of PTR > incref(); // constructor reference calculation plus 1
        }
    }

    ...

  ~TC_AutoPtr()
    {
        if(_ptr)
        {
            A kind of PTR > decref(); // destructor reference calculation minus 1
        }
    }
}

Example: use of actual combat projects

struct ConnStruct : public TC_HandleBase{...}

typedef TC_AutoPtr<ConnStruct> ConnStructPtr;

TC_AutoPtrCopy construct call_ptr->incRef();hereptrbyConnStructConnStructInherited fromTC_HandleBase, is equal to callingTC_HandleBaseT<int>::incRef() {++_atomic;}

The atomic operation of reference count is increased by 1, and the atomic operation of destruct reference count is subtracted by 1. When the reference count is reduced to 0, whether to trigger delete depends on whether the switch is set to delete.

Example: This is a typical example of tars using asynchronous RPC callbacks, where the callback class uses smart pointers

//Define the callback function smart pointer, where the sessioncallback parent class inherits from TC_ HandleBase
typedef TC_AutoPtr<SessionCallback> SessionCallbackPtr;  

//Create the callback class sessioncallbackptr and pass in the initialization parameter UIN gameid;
SessionCallbackPtr cb = new SessionCallback(iUin, iGameId, iSeqID, iCmd,sSessionID, theServant, current, cs, this);
//Asynchronously calling the session server remote interface
getSessionPrx()->async_getSession(cb, iUin, iGameId);

Interface return completion, callbackSessionCallback::callback_getSession(tars::Int32 ret, const MGComm::SessionValue& retValue)Function, receivesessionserverInterfaceSessionValueStructure.

becauseSessionCallbackPtrThe intelligent pointer is used, so the business does not need to release the front manuallynewIt came outSessionCallbackPtrIt’s more convenient.

MySQL operation class: TC_ Mysql

TC_ The MySQL operation class encapsulated by MySQL is non thread safe. It can have better function encapsulation for insert / update to prevent SQL injection

Usage:

TC_Mysql mysql;
//When MySQL is initialized, it will not be linked when init, but will be linked automatically when requested;
//The database can be empty;
//The default port is 3306
mysql.init("192.168.1.2", "pc", "[email protected]", "db_tars_demo");

Usually used:void init(const TC_DBConf& tcDBConf);Initialize the database directly. For example:stDirectMysql.init(_stZoneDirectDBConf);

look downTC_DBConfDefinition of

struct TC_DBConf
{
    string _host;
    string _user;
    string _password;
    string _database;
    string _charset;
    int _port;
    int _ Flag; // client ID

    TC_DBConf()
        : _port(0)
        , _flag(0)
    {}

    /**
    *@ brief read the database configuration 
    * 
    *@ param mpparam stores the map of database configuration 
    *Dbhost: host address
    *Dbuser: user name
    *Dbpass: password
    *Dbname: database name
    *Dbport: Port
    */
    void loadFromMap(const map<string, string> &mpParam)
    {
        map<string, string> mpTmp = mpParam;

        _host        = mpTmp["dbhost"];
        _user        = mpTmp["dbuser"];
        _password    = mpTmp["dbpass"];
        _database    = mpTmp["dbname"];
        _charset     = mpTmp["charset"];
        _port        = atoi(mpTmp["dbport"].c_str());
        _flag        = 0;

        if(mpTmp["dbport"] == "")
        {
            _port = 3306;
        }
    }
};
//Take a closer look at the use of data acquisition
TC_Mysql::MysqlData data;
data = mysql.queryRecord("select * from t_app_users");
for(size_t i = 0; i < data.size(); i++)
{
    //If there is no ID field, an exception is thrown
    cout << data[i]["ID"] << endl;
}

Query the MySQL data withMysqlDataencapsulation

class MysqlData
{  ...
    vector<map<string, string> >& data();      
   ...
}
//Insert data, specify the type of data: numeric value or string, for which string will be automatically escaped
map<string, pair<TC_Mysql::FT, string> > m;
m["ID"]     = make_pair(TC_Mysql::DB_INT, "2334");
m["USERID"] = make_pair(TC_Mysql::DB_STR, "abcttt");
m["APP"]    = make_pair(TC_Mysql::DB_STR, "abcapbbp");
m["LASTTIME"]    = make_pair(TC_Mysql::DB_INT, "now()");

mysql.replaceRecord("t_user_logs", m);

Network components

The whole tars core provides a very perfect network framework, including RPC function. Here, only a few common network components are introduced.

TC_ Socket: encapsulates the basic method of socket

It provides socket operation class, supports TCP / UDP socket, and supports local domain socket.

And the next tars packageTC_TCPClientandTC_UDPClientTwo classes are used to operate TCP and UDP applications.

Usage:

For example: TCP client

TC_TCPClient stRouterClient;

stRouterClient.init (sIP, iPort, iTimeOut); // here incoming IP and port, then calling sendRecv for sending and receiving messages.

Int32 ret = stRouterClient.sendRecv(request.c_str(), request.length(), recvBuf, iRecvLen);

Note that when multithreading is used, multiple threads cannot send / recv at the same time, and be careful of string packets.

TC_Epoller

It provides the operation class of network epoll, which is the ET mode by default. When the state changes, it will be informed. Basic operations such as add, mod, del and wait are provided.

TC_ ClientSocket: the base class of operation related to client socket

Provide key member functionsinit(const string &sIp, int iPort, int iTimeout), incoming IP port and timeout

TC_TCPClientInherited fromTC_ClientSocketProvide member functions:

  • sendRecv(send to the server, return no more than irecvlen bytes from the server)
  • sendRecvBySep(send the server down and wait for the server to reach the end character, including the ending character)

example:

stRouterClient.init(sIP, iPort, iTimeOut);

size_t iRecvLen = sizeof(recvBuf)-1;
Int32 ret = stRouterClient.sendRecv(request.c_str(), request.length(), recvBuf, iRecvLen);

In the same wayTC_UDPClientImplement UDP client.

Command parsing class: TC_ Option

  1. Command parsing class;
  2. It is usually used to parse command line parameters;
  3. Only double – parameter form is supported
  4. analysismainThe following forms of parameters are supported:
./main.exe --name=value --param1 param2 param3
TC_Option op;
//Parse command line
op.decode(argc, argv);
//Get pairs of parameters, that is, get all the parameter pairs represented by -
map<string, string> mp = op.getMulti();
//Param2 and param3 are the parameters of non -: param2 and param3
vector<string> d = op.getSingle();

If value, param has spaces or--You can use quotation marks.

Profile class: TC_ Config

  1. Configuration file parsing class (compatible with WBL mode);
  2. Support parsing configuration files from string;
  3. Support the generation of configuration files;
  4. Parse error, throw exception;
  5. Use [] to get the configuration. If there is no configuration, an exception will be thrown;
  6. Get the configuration by get. If it does not exist, it will return null;
  7. Reading configuration files is thread safe, and functions such as insert domain are not thread safe

example:

TC_Config config;
config.parseFile(ServerConfig::BasePath + ServerConfig::ServerName + ".conf");
stTmpGameServerConfig.iGameId = TC_Common::strto<UInt32>(config["/Main/<GameId>"]);

Sample configuration file

<Main>
    GameId = 3001
    ZoneId = 102
    AsyncThreadCheckInterval = 1000
    ...
</Main>

usegetMethod example: if the configuration cannot be read, the default value is returnedsDefaultIn the following example20000000

stTmpGameServerConfig.iMaxRegNum = TC_Common::strto<Int32>(config.get("/Main/<MaxRegNum>", "20000000"));

Generic functor class: TC_ Functor

TC_Functorreference resourceslokiDesign of Library

  1. In other words, we can add a pair of parentheses on the right side of the above methods, and put a set of appropriate parameters inside the brackets to call, for examplea(p1,p2);
  2. Encapsulate the whole call (including parameters) into a function object. The parameters are passed in when the call object is created, and no parameters are required during the call, such asA a(p1, p2); a();

The package is simple and easy to use. See the following examples for details

C function call

void TestFunction3(const string &s, int i){
    cout << "TestFunction3('" << s << "', '" << i << "')" << endl;   
}
//Using function pointer to construct object
TC_Functor<void, TL::TLMaker<const string&, int>::Result > cmd3(TestFunction3);
string s3("s3");
cmd3(s3, 10);

C function calls are encapsulated with wrapper

//Call encapsulation and pass in parameters when constructing

TC_Functor<void,TL::TLMaker<const string&, int>::Result>::wrapper_type fwrapper3(cmd3, s3, 10);
Fwrapper3(); // the parameter has been passed in during the construction, so it is not necessary to pass the parameter when calling

explain:

  • void: the return value of the function
  • TL::TLMaker<const string&, int>::Result: represents the parameter type

For the encapsulation of the call, pay attention to the reference type, and ensure the existence of the referenced object during the specific call.

C + + calls to class member functions

struct TestMember
{
    void mem3(const string &s, int i)
    {
        cout << "TestMember::mem3(" << s << "," << i << ") called" << endl;
    }
}
TC_Functor<void, TL::TLMaker<const string&, int>::Result > cmd3(&tm, &TestMember::mem3);
cmd3("a", 33);

The call to the class member function is encapsulated with wrapper

TC_Functor<void, TL::TLMaker<const string&, int>::Result >::wrapper_type fwrapper3(cmd3, "a", 10);
fwrapper3();

Practical example: register Protocol parser

When the service initializes initialize, it will call

addServantProtocol(sRouterObj, AppProtocol::parseStream<0, uint16_t, false>,iHeaderLen);

Set up hereBindAdapterProtocol parsing function ofprotocol_functor _pfbyparseStreamFunction, as follows:

/**
 * @param T
 * @param offset
 * @param netorder
 * @param in
 * @param out
 * @return int
 */
template<size_t offset, typename T, bool netorder>
static TC_NetWorkBuffer::PACKET_TYPE parseStream(TC_NetWorkBuffer& in,vector<char>& out)
{
    size_t len = offset + sizeof(T);

    if (in.getBufferLength() < len)
    {
        return TC_NetWorkBuffer::PACKET_LESS;
    }

    string header;
    in.getHeader(len, header);

    assert(header.size() == len);

    T iHeaderLen = 0;

    ::memcpy(&iHeaderLen, header.c_str() + offset, sizeof(T));

    if (netorder)
    {
        iHeaderLen = net2host<T>(iHeaderLen);
    }

    //Protect the length
    if (iHeaderLen < (T)(len) || (uint32_t)iHeaderLen > TARS_NET_MAX_PACKAGE_SIZE)
    {
        return TC_NetWorkBuffer::PACKET_ERR;
    }

    if (in.getBufferLength() < (uint32_t)iHeaderLen)
    {
        return TC_NetWorkBuffer::PACKET_LESS;
    }

    in.getHeader(iHeaderLen, out);

    assert(out.size() == iHeaderLen);

    in.moveHeader(iHeaderLen);

    return TC_NetWorkBuffer::PACKET_FULL;
}

After registering the parsing function, the network layer receives packets and callsparseProtocolfunction

int TC_EpollServer::Connection::parseProtocol(TC_NetWorkBuffer &rbuf)
{
    ...
    TC_ NetWorkBuffer::PACKET_ TYPE b = _ Pbindadapter > getprotocol() (rbuf, RO); // call back the previously set protocol resolution function to implement protocol resolution
    ...
}

Hash algorithm

util/tc_hash_fun.hIt includes the implementation of hash algorithmhash_newYou can hash the input byte stream to get a fairly uniform hash value. The usage is as follows

#include "util/tc_hash_fun.h"
#include <iterator>
#include <iostream>
#include <sys/time.h>

using namespace tars;
using namespace std;

int main(int argc, char* *argv[])
{
    unsigned int i = tars::hash_new<string>()("abcd");
    cout << i << endl;
    return 0;
}

Exception class: TC_ Exception

class TC_Exception : public exception
{  
    /**
     *The @ brief constructor provides a constructor that can be passed into errno, 
     *The error information directly obtained when an exception is thrown
     *  
     *Alarm information of @ param buffer exception 
     *@ param err error code. StrError can be used to obtain error information
     */
    TC_Exception(const string &buffer, int err);  
}

summary

This paper introduces and analyzes the common basic components implemented by C + + in tars framework, deepens the understanding of these basic components of tool classes, reduces the problems in the process of using these components, and improves the development efficiency.

Tars can quickly build the system and automatically generate code while considering the ease of use and high performance. It can help developers and enterprises to quickly build their own stable and reliable distributed applications in the way of microservices, so that developers can only focus on business logic and improve operational efficiency. Multi language, agile R & D, high availability and efficient operation make tars an enterprise level product.

Tars microservices help you with digital transformation. Welcome to:

Tars website: https://TarsCloud.org

Tars source code: https://github.com/TarsCloud

Access to tars official training eBook: https://wj.qq.com/s2/6570357/…

Or scan the code to obtain:

Basic components of microservice open source framework tars

Recommended Today

Java security framework

The article is mainly divided into three parts1. The architecture and core components of spring security are as follows: (1) authentication; (2) authority interception; (3) database management; (4) authority caching; (5) custom decision making; and;2. To build and use the environment, the current popular spring boot is used to build the environment, and the actual […]