My Sina Weibo: http://weibo.com/freshairbrucewoo.
You are welcome to exchange ideas and improve your technology together.
This part of related classes mainly implement protocol-related content. The protocol mentioned here refers to the Protocol encapsulated in the data transmission format. Different protocols are implemented to be suitable for data transmission in different scenarios, because different protocols vary greatly in different scenarios for data transmission efficiency. The following is the class relationship diagram of the related classes:
The above class diagram shows that all protocol classes are directly or indirectly inherited from the TProtocol class, and each protocol class has a corresponding production object Factory (Protocol factory ). TProtocol is an abstract class that cannot be directly used. It has a direct subclass that implements all methods by default (empty implementations ), if we need to define our own data transmission protocol, we can directly inherit from this class.
Section 1 class inheritance Architecture Analysis
Why do we need to analyze the class inheritance architecture? Isn't there a clear class inheritance relationship diagram above? However, in its implementation, Facebook does not simply inherit it, facebook adds an inheritance relationship to the protocol for later Protocol scalability and allows other organizations, teams, or individuals to implement their own data transmission (mainly data format encapsulation, it is the TVirtualProtocol class in the class diagram. It can be seen from the class name that this is a virtual protocol. How can we understand this virtual protocol? After reading the code, I think it can be understood as follows: because it is defined as a template class, this template class has two parameters, one is the real protocol used for data transmission, and the other is used for inheritance, it does not implement the specific content of the protocol, so it is a virtual protocol class. Next we will analyze this class inheritance architecture in combination with code implementation.
1 abstract class TProtocol and default implementation class TProtocolDefaults
Abstract classes provide the start and end methods of reading and writing for each type of data. Here, the Read and Write method should be for network I/O read and write, but the actual implementation of network read and write is not here, the method here mainly processes data, for example, adjusting the data format. The real implementation of network I/O read/write is the implementation of the TTransport-related classes introduced in the next chapter, where it also controls the transmission mode, such as whether to compress.
In addition to the specific data types, there are writing and reading methods. Messages also need to be transmitted over the network, so the Read and Write methods for message transmission are also defined. Of course, some common functions are also defined, such as skipping a structure that is not read, adjusting the data format on the Size end, and converting the host's byte sequence and network's byte sequence.
(1) first define pure virtual functions:
1 virtual uint32_t writeMessageBegin_virt(const std::string& name,2 3 const TMessageType messageType, const int32_t seqid) = 0;4 5 virtual uint32_t writeMessageEnd_virt() = 0;6 7 virtual uint32_t writeStructBegin_virt(const char* name) = 0;8 9 virtual uint32_t writeStructEnd_virt() = 0;
(2) then define the function that calls the corresponding pure virtual function:
1 uint32_t writeMessageBegin (const std: string & name, const TMessageType messageType, const int32_t seqid) {2 3 T_VIRTUAL_CALL (); // print call log function 4 5 return handler (name, messageType, seqid); 6 7} 8 9 uint32_t writeMessageEnd () {10 11 T_VIRTUAL_CALL (); 12 13 return writeMessageEnd_virt (); 14 15} 16 17 uint32_t writeStructBegin (const char * name) {// write struct start 18 19 T_VIRTUAL_CALL (); 20 21 return writestructbegbegin_virt (name ); 22 23} 24 25 uint32_t writeStructEnd () {// write struct end 26 27 T_VIRTUAL_CALL (); 28 29 return writeStructEnd_virt (); 30 31}
(3) Other public functions
1 uint32_t skip (TType type) {2 3 T_VIRTUAL_CALL (); 4 5 return skip_virt (type); // skip Data type 6 7} 8 9 virtual uint32_t skip_virt (TType type) {10 11 return: apache: thrift: protocol: skip (* this, type); // call the global function implementation in this namespace 12 13}
(4) global data structure definition
1 enum TType {// data type enumeration supported by Thrift Protocol definition 2 3 T_STOP = 0, 4 5 T_VOID = 1, 6 7 T_BOOL = 2, 8 9 T_BYTE = 11 T_I08 = 12 13 T_I16 = 6, 14 15 T_I32 = 8, 16 17 T_U64 = T_I64 = 10, 20 21 T_DOUBLE = 22 23 T_STRING = 11,24 25 T_UTF7 = 11,26 27 T_STRUCT = 1738 29 T_MAP = 13, 30 31 T_SET = 14, 32 33 T_LIST = 15, 34 35 T_UTF8 = 16, 36 37 T_UTF16 = 39 }; 40 41 enum TMessageType {// Message Type supported by thrift 42 43 T_CALL = 45 T_REPLY = 47 T_EXCEPTION = 49 T_ONEWAY = 4 // asynchronous function call Method 50 51 };
A corresponding abstract factory class is also defined for the specific Protocol objects of the production, which is the most common Abstract Factory Design Pattern in the design pattern. The code above just briefly lists two writing functions, and there are many other related data types for writing and reading functions because they are defined in the same format and are not described in detail.
As for the default implementation class TProtocolDefaults, the non-virtualized methods of the abstract class TProtocol are overwritten. All these methods throw an exception for implementation (TProtocolException: NOT_IMPLEMENTED. The main purpose of this operation is to provide the default inheritance base class for the class TVirtualProtocol mentioned below, so as to prevent infinite recursive calls. The following describes how to generate an infinite recursive call without the default implementation class.
2. Virtual protocols
First, let's take a look at how this special template class is defined:
1 template <class Protocol _, class Super _ = TProtocolDefaults> 2 3 class TVirtualProtocol: public Super _ {4 5 ...... // Omit content 6 7}
Specifically, I think it is mainly based on two aspects:
(1) The inherited class can be passed through the template parameters. That is to say, you cannot determine which class it inherits now, the default parameter value is the default implementation class of the abstract class we introduced above.
(2) All methods in the class are implemented by converting the this pointer to the type of the first template parameter and then calling the method related to the template parameter type. The following method is defined:
1 virtual uint32_t writeMessageBegin_virt (const std: string & name, 2 3 const TMessageType messageType, const int32_t seqid) {4 5 return static_cast <Protocol _ *> (this) -> writeMessageBegin (name, messageType, seqid); 6 7} // implement the writeMessageBegin_virt method of the abstract class
From the above two features, we can find that this class only provides an empty architecture shell, and the inherited class can be specified. Of course, the default class can also be used, after analyzing the implementation of specific protocols, we can find that most protocols use the default inheritance class, and most classes that inherit this virtual Protocol pass the first parameter as themselves, that is, call the corresponding function defined by yourself. For example, the TBinaryProtocolT class is defined as follows:
1 template <class Transport_>2 3 class TBinaryProtocolT : public TVirtualProtocol< TBinaryProtocolT<Transport_> > {4 5 …….6 7 }
The following describes how to generate an infinite recursive call without inheriting from the defined default implementation class. Now let's assume that we inherit from the abstract class directly. If a parent class (TProtocol) pointing to the subclass object calls the writeMessageBegin method, because this method is not a virtual function (it will not be dynamically bound) therefore, the writeMessageBegin method of the parent class will be called, and the parent class will directly call its pure virtual function writeMessageBegin_virt. This function will be dynamically bound and will implement the subclass, this is implemented through the Virtual Protocol Class TVirtualProtocol, and this function will call the writeMessageBegin method. If the subclass does not implement this method, it will return to the parent class, this produces infinite recursive calls. If the default value is inherited from the default implementation class TProtocolDefaults, its writeMessageBegin method will be executed, and an exception will be thrown, without infinite recursive calls.
3. Specific Protocol Class or self-implemented Protocol Class
This is the last part of the class inheritance architecture, that is, the implementation of specific data transmission protocols. For example, the binary Protocol Class is defined as follows:
1 template <class Transport_>2 3 class TBinaryProtocolT : public TVirtualProtocol< TBinaryProtocolT<Transport_> > { …… }
Then the binary protocol class does not need to implement those virtual methods. The specific protocol implementation methods are described in detail later.
Now the class inheritance architecture has been analyzed, and several important protocols implemented in Thrift will be introduced later.