├── .gitignore ├── framework ├── aliased_streambuf.h ├── application.cpp ├── application.h ├── atomic_int.h ├── base_reactor.h ├── bidirection_hashmap.h ├── buffer.cpp ├── buffer.h ├── circular_queue.h ├── consistent_hash.h ├── day_roll_logger.cpp ├── day_roll_logger.h ├── epoll_reactor.cpp ├── epoll_reactor.h ├── eventfd_handler.cpp ├── eventfd_handler.h ├── fsm_manager.cpp ├── fsm_manager.h ├── io_handler.h ├── ip_range_container.cpp ├── ip_range_container.h ├── linked_map.h ├── log_thread.cpp ├── log_thread.h ├── makefile ├── member_function_bind.h ├── mmap_file.cpp ├── mmap_file.h ├── network_util.cpp ├── network_util.h ├── object_pool.h ├── object_switcher.h ├── observer_manager.cpp ├── observer_manager.h ├── packet.h ├── packet_processor.h ├── pipe_handler.cpp ├── pipe_handler.h ├── poll_reactor.cpp ├── poll_reactor.h ├── queue_handler.h ├── string_util.cpp ├── string_util.h ├── system_util.cpp ├── system_util.h ├── tcp_acceptor.cpp ├── tcp_acceptor.h ├── tcp_data_handler.cpp ├── tcp_data_handler.h ├── thread.cpp ├── thread.h ├── time_util.h ├── timer_manager.cpp ├── timer_manager.h ├── udp_data_handler.cpp ├── udp_data_handler.h ├── unix_config.cpp └── unix_config.h ├── makefile ├── public ├── makefile ├── message.h ├── server_handler.cpp ├── server_handler.h ├── server_manager.cpp ├── server_manager.h ├── system.pb.cc ├── system.pb.h ├── system.proto └── template_packet.h ├── queue_server ├── async_processor_manager.cpp ├── async_processor_manager.h ├── client_tcp_handler.cpp ├── client_tcp_handler.h ├── client_udp_handler.cpp ├── client_udp_handler.h ├── config.json ├── makefile ├── queue.cpp ├── queue.h ├── queue_processor.cpp ├── queue_processor.h ├── queue_server.cpp ├── queue_server.h ├── server_ctl.sh ├── worker.cpp ├── worker.h ├── worker_util.cpp └── worker_util.h ├── rapidjson ├── allocators.h ├── document.h ├── encodedstream.h ├── encodings.h ├── error │ ├── en.h │ └── error.h ├── filereadstream.h ├── filewritestream.h ├── fwd.h ├── internal │ ├── biginteger.h │ ├── diyfp.h │ ├── dtoa.h │ ├── ieee754.h │ ├── itoa.h │ ├── meta.h │ ├── pow10.h │ ├── regex.h │ ├── stack.h │ ├── strfunc.h │ ├── strtod.h │ └── swap.h ├── istreamwrapper.h ├── memorybuffer.h ├── memorystream.h ├── msinttypes │ ├── inttypes.h │ └── stdint.h ├── ostreamwrapper.h ├── pointer.h ├── prettywriter.h ├── rapidjson.h ├── reader.h ├── schema.h ├── stream.h ├── stringbuffer.h └── writer.h ├── readme.md └── test ├── bench_queue.py └── test_queue.php /.gitignore: -------------------------------------------------------------------------------- 1 | *.d 2 | *.o 3 | *.a 4 | *.so 5 | *.bin 6 | *.log 7 | .* 8 | -------------------------------------------------------------------------------- /framework/aliased_streambuf.h: -------------------------------------------------------------------------------- 1 | /** 2 | * aliased_streambuf.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | namespace framework 12 | { 13 | 14 | /** 15 | * streambuf wrapper for protobuf 16 | */ 17 | class aliased_streambuf : public std::basic_streambuf 18 | { 19 | public: 20 | typedef std::basic_streambuf parent_type ; 21 | public: 22 | aliased_streambuf(char* buf,int size) 23 | { 24 | this->setp(buf,buf + size) ; 25 | 26 | this->setg(buf,buf,buf + size ) ; 27 | } 28 | 29 | protected: 30 | virtual int_type overflow(int_type c ) 31 | { 32 | if(this->pptr() < this->epptr() ) 33 | { 34 | 35 | return traits_type::to_int_type(*this->pptr()); 36 | } 37 | 38 | return traits_type::eof() ; 39 | } 40 | 41 | virtual int_type underflow() 42 | { 43 | if (this->gptr() < this->egptr()) 44 | { 45 | return traits_type::to_int_type(*this->gptr()); 46 | } 47 | 48 | return traits_type::eof(); 49 | 50 | } 51 | 52 | virtual int sync() 53 | { 54 | return 0 ; 55 | } 56 | 57 | virtual parent_type* setbuf( char * s, std::streamsize n ) 58 | { 59 | return this ; 60 | } 61 | 62 | virtual pos_type seekoff(off_type off, std::ios_base::seekdir way, std::ios_base::openmode mode) 63 | { 64 | pos_type ret = pos_type(off_type(-1)); 65 | off_type newoffi = 0 , newoffo = 0 ; 66 | if(way == std::ios_base::cur) 67 | { 68 | if(mode & std::ios_base::in) 69 | { 70 | newoffi = this->gptr() - this->eback() + off ; 71 | } 72 | 73 | if(mode & std::ios_base::out) 74 | { 75 | newoffi = this->pptr() - this->pbase() + off ; 76 | } 77 | } 78 | else if(way == std::ios_base::end) 79 | { 80 | if(mode & std::ios_base::in) 81 | { 82 | newoffi = this->egptr() - this->eback() + off ; 83 | } 84 | 85 | if(mode & std::ios_base::out) 86 | { 87 | newoffo = this->epptr() - this->pbase() + off ; 88 | } 89 | 90 | } 91 | 92 | if( (mode & std::ios_base::in) && newoffi >= 0 && newoffi < this->egptr() - this->eback() ) 93 | { 94 | this->gbump( this->eback() + newoffi - this->gptr()) ; 95 | ret = pos_type(newoffi) ; 96 | } 97 | 98 | if((mode & std::ios_base::out) && newoffo >=0 && newoffo < this->epptr() - this->pbase() ) 99 | { 100 | this->pbump( this->pbase() + newoffi - this->pptr()) ; 101 | ret = pos_type(newoffi) ; 102 | } 103 | 104 | 105 | return ret ; 106 | } 107 | 108 | virtual pos_type seekpos(pos_type, std::ios_base::openmode ) 109 | { 110 | return -1 ; 111 | } 112 | 113 | virtual std::streamsize showmanyc() 114 | { 115 | return 0 ; 116 | } 117 | 118 | 119 | 120 | /* 121 | virtual pos_type seekpos(pos_type, ios_base::openmode) 122 | { 123 | return -1 ; 124 | } 125 | 126 | */ 127 | 128 | 129 | 130 | } ; 131 | 132 | } 133 | 134 | -------------------------------------------------------------------------------- /framework/atomic_int.h: -------------------------------------------------------------------------------- 1 | /** 2 | * atomic_int.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | namespace framework 12 | { 13 | 14 | template 15 | class atomic_int 16 | { 17 | public: 18 | typedef T int_type ; 19 | 20 | atomic_int():m_counter(0) { } ; 21 | ~atomic_int() { } ; 22 | 23 | 24 | /** 25 | * brief atomically read value 26 | */ 27 | int_type get() { return m_counter ; } ; 28 | 29 | /** 30 | * @brief atomically set value 31 | * @return old value 32 | */ 33 | int_type set(int_type v) { return __sync_lock_test_and_set(&m_counter,v) ; } ; 34 | 35 | /** 36 | * @brief atomically add a value and return new value 37 | * @param [in]: integer value to add 38 | * @return old value 39 | */ 40 | int_type add(int_type i) { return __sync_fetch_and_add(&m_counter,i) ; } ; 41 | 42 | /** 43 | * @brief atomically sub a value and return new value 44 | * @param [in]: integer value to sub 45 | * @return old value 46 | */ 47 | int_type sub(int_type i) { return __sync_fetch_and_sub(&m_counter,i) ; } ; 48 | 49 | /** 50 | * @brief compare and switch 51 | * @param [in]: old value 52 | * @param [in]: new value 53 | * @return true on success 54 | */ 55 | bool cas(int_type old_value,int_type new_value) 56 | { 57 | return __sync_bool_compare_and_swap(&m_counter,old_value,new_value); 58 | } ; 59 | 60 | 61 | 62 | 63 | private: 64 | volatile int_type m_counter ; 65 | 66 | }; 67 | 68 | typedef atomic_int atomic_int8 ; 69 | typedef atomic_int atomic_int16 ; 70 | typedef atomic_int atomic_int32 ; 71 | typedef atomic_int atomic_int64 ; 72 | 73 | 74 | } 75 | 76 | -------------------------------------------------------------------------------- /framework/base_reactor.h: -------------------------------------------------------------------------------- 1 | /** 2 | * base_reactor.h 3 | * Author: lixingyi (lxyfirst@163.com) 4 | */ 5 | 6 | #pragma once 7 | 8 | namespace framework 9 | { 10 | 11 | class io_handler ; 12 | 13 | /** 14 | * @brief abstract class for io event reactor 15 | */ 16 | class base_reactor 17 | { 18 | public: 19 | enum event_type 20 | { 21 | EVENT_READ = 0x001 , 22 | EVENT_WRITE = 0x004 , 23 | } ; 24 | 25 | public: 26 | base_reactor(){ } ; 27 | virtual ~base_reactor() { } ; 28 | 29 | public: 30 | /** 31 | * @brief register fd handler to epoll engine 32 | * @param [in] fd to be watched 33 | * @param [in] handler to callback 34 | * @param [in] event type 35 | * @return 0 on success , nagtive on failed 36 | */ 37 | virtual int add_handler(int fd , io_handler* handler,int event_type) =0; 38 | 39 | /** 40 | * @brief modify fd watched 41 | * @param [in] fd have been watched 42 | * @param [in] handler to callback 43 | * @param [in] event type 44 | * @return 0 on success 45 | */ 46 | virtual int mod_handler(int fd , io_handler* handler ,int event_type ) =0; 47 | 48 | /** 49 | * @brief remove fd watched 50 | * @param [in] fd have been watched 51 | */ 52 | virtual void del_handler(int fd ) =0; 53 | 54 | /** 55 | * @brief get handler by fd 56 | * @param [in] fd have been watched 57 | * @return handler pointer , NULL is not exist 58 | */ 59 | virtual io_handler* get_handler(int fd) =0 ; 60 | 61 | /** 62 | * @brief watch events one time , will block msec milliseconds at most 63 | * @param [in] max milliseconds to wait 64 | * @return events count 65 | */ 66 | virtual int run_once(int msec) =0; 67 | 68 | 69 | private: 70 | base_reactor(const base_reactor& ) ; 71 | base_reactor& operator=(const base_reactor&) ; 72 | 73 | }; 74 | 75 | } 76 | 77 | 78 | -------------------------------------------------------------------------------- /framework/bidirection_hashmap.h: -------------------------------------------------------------------------------- 1 | /** 2 | * bidirection_hashmap.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | 12 | namespace framework 13 | { 14 | 15 | /** 16 | * @brief didirection hashmap 17 | */ 18 | template 19 | class bidirection_hashmap 20 | { 21 | public: 22 | typedef std::pair value_type ; 23 | typedef std::tr1::unordered_map first_index ; 24 | typedef std::tr1::unordered_map second_index ; 25 | 26 | public: 27 | 28 | ~bidirection_hashmap() 29 | { 30 | for(typename first_index::iterator it = m_first_index.begin();it!=m_first_index.end();++it) 31 | { 32 | delete it->second ; 33 | } 34 | } 35 | 36 | bool insert(const T1& v1,const T2& v2) 37 | { 38 | if( m_first_index.count(v1) >0 || m_second_index.count(v2) > 0 ) 39 | { 40 | return false ; 41 | } 42 | 43 | value_type* value = new value_type(v1,v2) ; 44 | if(value == NULL ) return false ; 45 | 46 | m_first_index[v1] = value ; 47 | m_second_index[v2] = value ; 48 | 49 | return true ; 50 | } 51 | 52 | void erase_by_first(const T1& v1) 53 | { 54 | typename first_index::iterator it = m_first_index.find(v1) ; 55 | if(it != m_first_index.end() ) 56 | { 57 | value_type* value = it->second ; 58 | m_second_index.erase(value->second) ; 59 | m_first_index.erase(it) ; 60 | delete value ; 61 | } 62 | } 63 | 64 | void erase_by_second(const T2& v2) 65 | { 66 | typename second_index::iterator it = m_second_index.find(v2) ; 67 | if(it != m_second_index.end() ) 68 | { 69 | value_type* value = it->second ; 70 | m_first_index.erase(value->second) ; 71 | m_second_index.erase(it) ; 72 | delete value ; 73 | } 74 | 75 | } 76 | 77 | const T2* find_by_first(const T1& v1) const 78 | { 79 | typename first_index::const_iterator it = m_first_index.find(v1) ; 80 | if(it != m_first_index.end() ) return &it->second->second ; 81 | return NULL ; 82 | } 83 | 84 | const T1* find_by_second(const T2& v2) const 85 | { 86 | 87 | typename second_index::const_iterator it = m_second_index.find(v2) ; 88 | if(it != m_second_index.end() ) return &it->second->first ; 89 | return NULL ; 90 | } 91 | 92 | private: 93 | first_index m_first_index ; 94 | second_index m_second_index ; 95 | 96 | } ; 97 | 98 | 99 | } 100 | 101 | -------------------------------------------------------------------------------- /framework/buffer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * buffer.cpp 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "buffer.h" 11 | 12 | namespace framework 13 | { 14 | 15 | buffer::buffer():m_begin(NULL),m_end(NULL),m_data(NULL),m_space(NULL) 16 | { 17 | // TODO Auto-generated constructor stub 18 | 19 | } 20 | 21 | buffer::~buffer() 22 | { 23 | fini() ; 24 | } 25 | 26 | int buffer::init(int size) 27 | { 28 | if(size < 8 || m_begin != NULL ) return -1 ; 29 | m_begin = (char*)malloc(size) ; 30 | if(m_begin == NULL ) return -2 ; 31 | m_end = m_begin + size ; 32 | m_data = m_space = m_begin ; 33 | 34 | return 0 ; 35 | } 36 | 37 | void buffer::fini() 38 | { 39 | if(m_begin != NULL ) 40 | { 41 | free(m_begin) ; 42 | m_begin = m_end = m_data = m_space = NULL ; 43 | } 44 | } 45 | 46 | int buffer::resize(int size) 47 | { 48 | 49 | if( m_space - m_begin > size ) return -1 ; 50 | 51 | char* new_buffer = (char*)realloc(m_begin,size) ; 52 | if(new_buffer == NULL ) return -2 ; 53 | if(new_buffer == m_begin ) 54 | { 55 | m_end = m_begin + size ; 56 | } 57 | else 58 | { 59 | m_data = new_buffer + (m_data - m_begin) ; 60 | m_space = new_buffer + (m_space - m_begin) ; 61 | m_begin = new_buffer ; 62 | m_end = m_begin + size ; 63 | } 64 | 65 | return 0 ; 66 | 67 | } 68 | 69 | void buffer::adjust() 70 | { 71 | if(m_begin != NULL && (m_data - m_begin ) > (m_end - m_begin)/2 ) 72 | { 73 | int count = m_space - m_data ; 74 | memmove(m_begin,m_data,count ) ; 75 | m_data = m_begin ; 76 | m_space = m_begin + count ; 77 | } 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /framework/buffer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * buffer.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | namespace framework 10 | { 11 | 12 | /** 13 | * @brief data buffer which have independent read and write pointer , 14 | * caller must keep data and pointer correct 15 | */ 16 | class buffer 17 | { 18 | public: 19 | buffer(); 20 | ~buffer(); 21 | 22 | /** 23 | * @brief initialize and alloc memory 24 | * @param [in] memory size 25 | * @return 0 on success , -1 on failed 26 | */ 27 | int init(int size) ; 28 | 29 | /** 30 | * @brief free memroy 31 | */ 32 | void fini() ; 33 | 34 | /** 35 | * @brief resize memory 36 | */ 37 | int resize(int size) ; 38 | 39 | /** 40 | * @brief move data when read pointer > 1/4 total memory 41 | */ 42 | void adjust() ; 43 | 44 | int capacity() { return m_end - m_begin ; } ; 45 | 46 | /** 47 | * @brief data pointer for read 48 | */ 49 | char* data() { return m_data ; } ; 50 | int data_size() { return m_space - m_data ; } ; 51 | 52 | /** 53 | * @brief data ponter for write 54 | */ 55 | char* space() { return m_space ; } ; 56 | int space_size() { return m_end - m_space ; } ; 57 | 58 | /** 59 | * @brief move write pointer after shift in data 60 | */ 61 | int push_data(int count) 62 | { 63 | if(count < 1 || count > space_size() ) return -1 ; 64 | m_space += count ; 65 | return 0 ; 66 | } 67 | 68 | /** 69 | * @brief move read pointer after shift out data 70 | */ 71 | int pop_data(int count) 72 | { 73 | if(count < 1 || count > data_size() ) return -1 ; 74 | m_data += count ; 75 | if(m_data == m_space ) m_data = m_space = m_begin ; 76 | return 0 ; 77 | } 78 | 79 | /** 80 | * @brief clean up 81 | */ 82 | void clear() { m_data = m_space = m_begin ; } ; 83 | 84 | 85 | 86 | private: 87 | buffer(const buffer&) ; 88 | buffer& operator=(const buffer&) ; 89 | 90 | private: 91 | char* m_begin ; 92 | char* m_end ; 93 | char* m_data ; 94 | char* m_space ; 95 | }; 96 | 97 | } 98 | 99 | -------------------------------------------------------------------------------- /framework/circular_queue.h: -------------------------------------------------------------------------------- 1 | /** 2 | * circular_queue.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | #include 9 | #include 10 | 11 | namespace framework 12 | { 13 | /** 14 | * @brief spsc circular queue , push elements at the head and pop elements at the tail 15 | */ 16 | template 17 | class circular_queue 18 | { 19 | public: 20 | /** 21 | * @brief initialize the queue , allocate space 22 | */ 23 | int init(int maxsize) 24 | { 25 | if ( m_itemlist != NULL || maxsize < 4 ) return -1 ; 26 | 27 | m_itemlist = new T[maxsize] ; 28 | if ( m_itemlist == NULL ) return -1 ; 29 | 30 | m_maxsize = maxsize ; 31 | return 0 ; 32 | } ; 33 | 34 | /** 35 | * @brief clean up 36 | */ 37 | void fini() 38 | { 39 | if ( m_itemlist != NULL ) 40 | { 41 | delete[] m_itemlist ; 42 | m_itemlist = NULL ; 43 | m_front = m_back = 0 ; 44 | 45 | } 46 | 47 | } ; 48 | 49 | /** 50 | * @brief get the queue capacity size 51 | */ 52 | int capacity() const { return m_maxsize ;} ; 53 | /** 54 | * @brief check the queue is empty 55 | * @return true if empty 56 | */ 57 | bool empty() const { return m_front == m_back ;} ; 58 | /** 59 | * @brief check the queue is full 60 | * @return true if full 61 | */ 62 | bool full() const {return (m_front +1) % m_maxsize == m_back ; } ; 63 | 64 | /** 65 | * @brief push element at the head 66 | */ 67 | int push(const T& element) 68 | { 69 | if ( m_itemlist == NULL || full() ) return -1 ; 70 | m_itemlist[m_front] = element ; 71 | m_front = (m_front +1) % m_maxsize ; 72 | return 0 ; 73 | } 74 | 75 | /** 76 | * @brief pop element at the tail 77 | */ 78 | int pop(T& element) 79 | { 80 | if ( m_itemlist == NULL || empty() ) return -1 ; 81 | element = m_itemlist[m_back] ; 82 | m_back = (m_back +1) % m_maxsize ; 83 | return 0 ; 84 | } 85 | 86 | 87 | /** 88 | * @brief get the tail element pointer 89 | */ 90 | T* back() 91 | { 92 | if (m_itemlist == NULL || empty() ) return NULL ; 93 | return m_itemlist + m_back ; 94 | } ; 95 | 96 | 97 | public: 98 | circular_queue():m_maxsize(1),m_itemlist(NULL),m_front(0),m_back(0){}; 99 | ~circular_queue() { fini(); } ; 100 | 101 | private: 102 | circular_queue(const circular_queue&) ; 103 | circular_queue& operator=(const circular_queue&) ; 104 | 105 | private: 106 | int m_maxsize ; 107 | T* m_itemlist ; 108 | volatile int m_front ; 109 | volatile int m_back ; 110 | 111 | }; 112 | 113 | } 114 | 115 | -------------------------------------------------------------------------------- /framework/consistent_hash.h: -------------------------------------------------------------------------------- 1 | /** 2 | * consistent_hash.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | namespace framework 13 | { 14 | 15 | 16 | /** 17 | * @brief consistent hash dispatcher 18 | */ 19 | class consistent_hash 20 | { 21 | public : 22 | 23 | consistent_hash(int mask= 0xFFFF,int vnode= 3):m_mask(mask),m_vnode(vnode){}; 24 | /** 25 | * @brief load config 26 | */ 27 | int set_node_list(const std::vector& node_list) 28 | { 29 | if(node_list.size() < 1 || m_vnode < 1 || m_mask < 1 ) return -1 ; 30 | clear() ; 31 | 32 | for(auto& node_value : node_list) add_node(node_value); 33 | 34 | return 0 ; 35 | 36 | } 37 | 38 | void clear() 39 | { 40 | m_circle_nodes.clear() ; 41 | } 42 | 43 | int add_node(int node_value) 44 | { 45 | if(m_vnode < 1 || m_mask < 1 ) return -1 ; 46 | for(int i = 0 ; i < m_vnode ; ++i) 47 | { 48 | int circle_value = (((int64_t)node_value * 156899) + i*m_mask/m_vnode) % m_mask ; 49 | m_circle_nodes[circle_value] = node_value ; 50 | } 51 | return 0 ; 52 | 53 | } 54 | 55 | void dump() 56 | { 57 | for(auto& kv : m_circle_nodes) printf("%d => %d\n",kv.first,kv.second) ; 58 | } 59 | 60 | /** 61 | * @brief 62 | */ 63 | inline int dispatch(int key) 64 | { 65 | if(m_circle_nodes.size() ==0) return -1 ; 66 | auto it = m_circle_nodes.lower_bound(key % m_mask) ; 67 | if( it == m_circle_nodes.end()) it = m_circle_nodes.begin() ; 68 | return it->second ; 69 | } 70 | 71 | 72 | private: 73 | std::map m_circle_nodes; 74 | int m_mask ; 75 | int m_vnode ; 76 | 77 | }; 78 | 79 | } 80 | 81 | 82 | -------------------------------------------------------------------------------- /framework/day_roll_logger.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * day_roll_logger.cpp 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "day_roll_logger.h" 14 | 15 | namespace framework 16 | { 17 | 18 | static const char* log_level_str[] = 19 | { 20 | "" , 21 | "error" , 22 | "warn" , 23 | "info" , 24 | "trace" , 25 | "debug" , 26 | "" 27 | } ; 28 | 29 | day_roll_logger::day_roll_logger():m_fd(-1),m_filedate(0) 30 | { 31 | memset(m_prefix,0,sizeof(m_prefix)) ; 32 | memset(m_buf,0,sizeof(m_buf)) ; 33 | 34 | } 35 | 36 | day_roll_logger::~day_roll_logger() 37 | { 38 | fini() ; 39 | } 40 | 41 | int day_roll_logger::init(const char* prefix,int log_level) 42 | { 43 | if ( prefix == NULL ) return -1 ; 44 | if ( log_level < LOG_LEVEL_MIN) log_level = LOG_LEVEL_MIN; 45 | if( log_level > LOG_LEVEL_MAX) log_level = LOG_LEVEL_MAX; 46 | 47 | m_level = log_level ; 48 | strncpy(m_prefix,prefix,sizeof(m_prefix)-1) ; 49 | 50 | tzset() ; 51 | return prepare() ; 52 | 53 | } 54 | void day_roll_logger::fini() 55 | { 56 | 57 | if ( m_fd >= 0 ) 58 | { 59 | close(m_fd) ; 60 | m_fd = -1 ; 61 | m_level = LOG_LEVEL_NONE ; 62 | m_filedate = 0 ; 63 | 64 | } 65 | 66 | } 67 | int day_roll_logger::prepare() 68 | { 69 | time_t t = time(NULL); 70 | if ( localtime_r(&t, &m_now) == NULL ) return -1 ; 71 | m_now.tm_year += 1900 ; 72 | m_now.tm_mon += 1 ; 73 | 74 | int curdate = ( m_now.tm_mon << 8 ) | m_now.tm_mday ; 75 | if (m_filedate != curdate ) 76 | { 77 | if(strcmp(m_prefix,"/dev/null")==0) return 0 ; 78 | char filename[MAX_PREFIX_SIZE + 64 ] = {0} ; 79 | snprintf(filename,sizeof(filename),"%s.%04d%02d%02d.log", 80 | m_prefix ,m_now.tm_year,m_now.tm_mon,m_now.tm_mday) ; 81 | int fd = open(filename,O_APPEND|O_WRONLY|O_CREAT,0777) ; 82 | if ( fd < 0 ) return -1 ; 83 | if ( m_fd >= 0 ) 84 | { 85 | close(m_fd) ; 86 | } 87 | m_fd = fd ; 88 | m_filedate = curdate ; 89 | } 90 | 91 | return 0 ; 92 | } 93 | 94 | int day_roll_logger::write_format(int ll,const char* fmt,...) 95 | { 96 | 97 | if ( m_fd < 0 || ll > m_level || ll < LOG_LEVEL_MIN) return -1 ; 98 | 99 | if ( prepare() != 0 ) return -1 ; 100 | 101 | int head_size = sprintf(m_buf ,"%02d-%02d %02d:%02d:%02d|%s|" , 102 | m_now.tm_mon,m_now.tm_mday,m_now.tm_hour,m_now.tm_min,m_now.tm_sec, 103 | log_level_str[ll] ) ; 104 | 105 | if(head_size < 0 ) return -2 ; 106 | 107 | va_list ap ; 108 | va_start(ap, fmt); 109 | int writable_size = sizeof(m_buf) - head_size -1 ; 110 | int content_size = vsnprintf(m_buf + head_size,writable_size,fmt,ap) ; 111 | va_end(ap); 112 | 113 | if(content_size < 0 ) return -2 ; 114 | else if ( content_size >= writable_size ) content_size = writable_size -1 ; 115 | 116 | content_size += head_size ; 117 | if ( m_buf[content_size -1] !='\n') 118 | { 119 | m_buf[content_size] = '\n' ; 120 | m_buf[++content_size] = '\0' ; 121 | } 122 | 123 | return write(m_fd,m_buf,content_size) ; 124 | 125 | } 126 | 127 | 128 | } 129 | -------------------------------------------------------------------------------- /framework/day_roll_logger.h: -------------------------------------------------------------------------------- 1 | /** 2 | * day_roll_logger.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | namespace framework 12 | { 13 | 14 | /** 15 | * @brief logger file rolled by day 16 | */ 17 | class day_roll_logger 18 | { 19 | public: 20 | enum 21 | { 22 | LOG_LEVEL_NONE = 0 , 23 | LOG_LEVEL_ERROR = 1 , 24 | LOG_LEVEL_WARN = 2 , 25 | LOG_LEVEL_INFO = 3 , 26 | LOG_LEVEL_TRACE= 4 , 27 | LOG_LEVEL_DEBUG = 5 , 28 | LOG_LEVEL_MIN = LOG_LEVEL_ERROR , 29 | LOG_LEVEL_MAX = LOG_LEVEL_DEBUG , 30 | } ; 31 | 32 | enum 33 | { 34 | MAX_PREFIX_SIZE = 1024 , 35 | MAX_LINE_SIZE = 2048 , 36 | }; 37 | 38 | public: 39 | /** 40 | * @brief initialize the logger 41 | * @param [in]: prefix - logger file prefix , prefix-xxxx-xx-xx.log 42 | * @param [in]: log level 43 | * @return 0 if success 44 | */ 45 | int init(const char* prefix,int log_level) ; 46 | 47 | /** 48 | * @brief clean up 49 | */ 50 | void fini() ; 51 | 52 | /** 53 | * @brief write formatted log data 54 | * @param [in] log level 55 | * @param [in] format string 56 | * @param [in] write data size 57 | */ 58 | int write_format(int log_level,const char* fmt,...) ; 59 | 60 | int write_string(int log_level,const char* content) 61 | { 62 | return this->write_format(log_level,"%s",content) ; 63 | } 64 | 65 | short get_level() { return m_level ; } ; 66 | const char* get_prefix() { return m_prefix ; } ; 67 | 68 | public: 69 | day_roll_logger(); 70 | ~day_roll_logger(); 71 | 72 | private: 73 | day_roll_logger(const day_roll_logger& ) ; 74 | day_roll_logger& operator=(const day_roll_logger&) ; 75 | 76 | private: 77 | int prepare() ; 78 | 79 | private: 80 | struct tm m_now ; 81 | int m_fd ; 82 | int m_filedate ; 83 | char m_level ; 84 | char m_prefix[MAX_PREFIX_SIZE] ; 85 | char m_buf[MAX_LINE_SIZE] ; 86 | 87 | }; 88 | 89 | #ifdef NDEBUG 90 | #define write_log_format(logger,level,fmt,args...) \ 91 | do{ logger.write_format(level,fmt,##args);} while(0) 92 | #define write_log_string(logger,level,content) \ 93 | do{ logger.write_string(level,content);} while(0) 94 | #else 95 | #define write_log_format(logger,level, fmt,args...) \ 96 | do{ logger.write_format(level,"[%s:%d]" fmt , __FILE__,__LINE__,##args);} while(0) 97 | #define write_log_string(logger,level,content) \ 98 | do{ logger.write_format(level,"[%s:%d]%s",__FILE__,__LINE__,content);} while(0) 99 | #endif 100 | 101 | 102 | #define error_log_format(logger, fmt ,args...) write_log_format(logger,framework::day_roll_logger::LOG_LEVEL_ERROR, fmt,##args) 103 | #define warn_log_format(logger, fmt ,args...) write_log_format(logger,framework::day_roll_logger::LOG_LEVEL_WARN, fmt,##args) 104 | #define info_log_format(logger, fmt ,args...) write_log_format(logger,framework::day_roll_logger::LOG_LEVEL_INFO, fmt,##args) 105 | #define trace_log_format(logger, fmt ,args...) write_log_format(logger,framework::day_roll_logger::LOG_LEVEL_TRACE, fmt,##args) 106 | 107 | #define error_log_string(logger,content) write_log_string(logger,framework::day_roll_logger::LOG_LEVEL_ERROR,content) 108 | #define warn_log_string(logger,content) write_log_string(logger,framework::day_roll_logger::LOG_LEVEL_WARN,content) 109 | #define info_log_string(logger,content) write_log_string(logger,framework::day_roll_logger::LOG_LEVEL_INFO,content) 110 | #define trace_log_string(logger,content) write_log_string(logger,framework::day_roll_logger::LOG_LEVEL_TRACE,content) 111 | 112 | #ifdef NDEBUG 113 | #define debug_log_format(logger,fmt,args...) 114 | #define debug_log_string(logger,content) 115 | #else 116 | #define debug_log_format(logger,fmt,args...) write_log_format(logger,framework::day_roll_logger::LOG_LEVEL_DEBUG,fmt,##args) 117 | #define debug_log_string(logger,content) write_log_format(logger,framework::day_roll_logger::LOG_LEVEL_DEBUG,content) 118 | #endif 119 | 120 | } 121 | 122 | -------------------------------------------------------------------------------- /framework/epoll_reactor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * epoll_reactor.cpp 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | #include "epoll_reactor.h" 14 | #include "io_handler.h" 15 | 16 | namespace framework 17 | { 18 | 19 | epoll_reactor::epoll_reactor():m_maxfd(0),m_epfd(-1),m_events(NULL),m_handlers(NULL) 20 | { 21 | 22 | 23 | } 24 | 25 | epoll_reactor::~epoll_reactor() 26 | { 27 | fini() ; 28 | } 29 | int epoll_reactor::init(int maxfd) 30 | { 31 | 32 | 33 | if ( maxfd < MIN_FD_SIZE || m_epfd >= 0 ) return -1 ; 34 | 35 | 36 | m_epfd = epoll_create(maxfd) ; 37 | if ( m_epfd < 0 ) return -1 ; 38 | 39 | int memsize = sizeof(struct epoll_event) * MAX_EVENTS_ONCE + sizeof(io_handler*) * maxfd ; 40 | char* membase = (char*)malloc(memsize) ; 41 | 42 | 43 | if (membase == NULL ) 44 | { 45 | close(m_epfd) ; 46 | return -1 ; 47 | } 48 | memset(membase,0,memsize) ; 49 | m_events = (struct epoll_event*)membase ; 50 | m_handlers = (io_handler**)(m_events + MAX_EVENTS_ONCE) ; 51 | 52 | 53 | m_maxfd = maxfd ; 54 | 55 | return 0 ; 56 | 57 | } 58 | void epoll_reactor::fini() 59 | { 60 | if ( m_epfd >= 0 ) 61 | { 62 | 63 | close(m_epfd) ; 64 | m_epfd = -1 ; 65 | free(m_events) ; 66 | m_events = NULL ; 67 | m_handlers = NULL ; 68 | 69 | 70 | } 71 | 72 | } 73 | 74 | io_handler* epoll_reactor::get_handler(int fd) 75 | { 76 | if(fd <0 || fd >= m_maxfd) return NULL ; 77 | return m_handlers[fd] ; 78 | } 79 | 80 | int epoll_reactor::add_handler(int fd, io_handler* h,int event_type) 81 | { 82 | 83 | if ( h == NULL || m_epfd < 0 ) return -1 ; 84 | if ( fd < 0 || fd >= m_maxfd ) return -2 ; 85 | 86 | struct epoll_event ev = {0} ; 87 | if ( event_type & EVENT_READ ) 88 | { 89 | ev.events |= EPOLLIN ; 90 | } 91 | 92 | if ( event_type & EVENT_WRITE ) 93 | { 94 | ev.events |= EPOLLOUT ; 95 | } 96 | 97 | //ev.events |= EPOLLET ; 98 | ev.data.fd = fd ; 99 | if ( epoll_ctl(m_epfd , EPOLL_CTL_ADD , fd ,&ev ) != 0 ) return -3 ; 100 | 101 | 102 | m_handlers[fd] = h ; 103 | 104 | return 0 ; 105 | 106 | } 107 | int epoll_reactor::mod_handler(int fd, io_handler* h ,int event_type ) 108 | { 109 | 110 | if ( h == NULL || m_epfd < 0 ) return -1 ; 111 | if ( fd < 0 || fd >= m_maxfd ) return -2 ; 112 | 113 | struct epoll_event ev = {0} ; 114 | if ( event_type & EVENT_READ ) 115 | { 116 | ev.events |= EPOLLIN ; 117 | } 118 | 119 | if ( event_type & EVENT_WRITE ) 120 | { 121 | ev.events |= EPOLLOUT ; 122 | } 123 | 124 | 125 | ev.data.fd = fd ; 126 | if ( epoll_ctl(m_epfd , EPOLL_CTL_MOD , fd ,&ev ) != 0 ) return -3 ; 127 | m_handlers[fd] = h ; 128 | 129 | return 0 ; 130 | } 131 | void epoll_reactor::del_handler(int fd) 132 | { 133 | if ( m_epfd < 0 ) return ; 134 | if ( fd < 0 || fd >= m_maxfd ) return ; 135 | 136 | epoll_ctl(m_epfd,EPOLL_CTL_DEL,fd ,NULL) ; 137 | 138 | m_handlers[fd] = NULL; 139 | 140 | } 141 | 142 | 143 | int epoll_reactor::run_once(int msec) 144 | { 145 | int n = epoll_wait(m_epfd,m_events,MAX_EVENTS_ONCE,msec) ; 146 | for(int i = 0 ; i < n ; ++i ) 147 | { 148 | const struct epoll_event* ev = m_events + i ; 149 | int fd = ev->data.fd ; 150 | 151 | if ( ev->events & (EPOLLPRI | EPOLLERR | EPOLLHUP) ) 152 | { 153 | if ( m_handlers[fd] != NULL) m_handlers[fd]->on_error(fd) ; 154 | } 155 | else 156 | { 157 | if ( ev->events & EPOLLOUT ) 158 | { 159 | if ( m_handlers[fd] != NULL) m_handlers[fd]->on_write(fd) ; 160 | } 161 | 162 | if ( ev->events & EPOLLIN ) 163 | { 164 | if ( m_handlers[fd] != NULL) m_handlers[fd]->on_read(fd) ; 165 | } 166 | } 167 | 168 | } 169 | 170 | return n ; 171 | 172 | } 173 | 174 | 175 | 176 | 177 | } 178 | -------------------------------------------------------------------------------- /framework/epoll_reactor.h: -------------------------------------------------------------------------------- 1 | /** 2 | * epoll_reactor.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "base_reactor.h" 10 | 11 | namespace framework 12 | { 13 | 14 | class io_handler ; 15 | 16 | /** 17 | * @brief epoll reactor 18 | */ 19 | class epoll_reactor : public base_reactor 20 | { 21 | public: 22 | enum 23 | { 24 | MIN_FD_SIZE = 8 , 25 | MAX_EVENTS_ONCE = 256 , 26 | } ; 27 | 28 | public: 29 | epoll_reactor(); 30 | ~epoll_reactor(); 31 | 32 | public: 33 | /** 34 | * @brief initialize , create epoll fd and alloc memory 35 | * @param [in] max fd slot 36 | * @return 0 on success , nagtive on failed 37 | */ 38 | int init(int maxfd) ; 39 | 40 | void fini() ; 41 | 42 | /** 43 | * @brief register fd handler to epoll engine 44 | * @param [in] fd to be watched 45 | * @param [in] handler to callback 46 | * @param [in] event type 47 | * @return 0 on success , nagtive on failed 48 | */ 49 | int add_handler(int fd , io_handler* handler,int event_type) ; 50 | 51 | /** 52 | * @brief modify fd watched 53 | * @param [in] fd have been watched 54 | * @param [in] handler to callback 55 | * @param [in] event type 56 | * @return 0 on success 57 | */ 58 | int mod_handler(int fd , io_handler* handler ,int event_type ) ; 59 | 60 | /** 61 | * @brief remove fd watched 62 | */ 63 | void del_handler(int fd ) ; 64 | 65 | io_handler* get_handler(int fd) ; 66 | 67 | /** 68 | * @brief watch events one time , will block msec milliseconds at most 69 | * @param [in] max milliseconds to wait 70 | * @return events count 71 | */ 72 | int run_once(int msec) ; 73 | 74 | 75 | private: 76 | epoll_reactor(const epoll_reactor& ) ; 77 | epoll_reactor& operator=(const epoll_reactor&) ; 78 | 79 | private: 80 | int m_maxfd ; 81 | int m_epfd ; 82 | struct epoll_event* m_events ; 83 | io_handler** m_handlers ; 84 | 85 | }; 86 | 87 | } 88 | 89 | -------------------------------------------------------------------------------- /framework/eventfd_handler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Author : lixingyi (lxyfirst@163.com) 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | #include "base_reactor.h" 10 | #include "eventfd_handler.h" 11 | 12 | 13 | 14 | namespace framework 15 | { 16 | 17 | 18 | eventfd_handler::eventfd_handler():m_reactor(NULL),m_event_fd(-1) 19 | { 20 | 21 | } 22 | 23 | eventfd_handler::~eventfd_handler() 24 | { 25 | fini(); 26 | } 27 | 28 | int eventfd_handler::init(base_reactor& reactor,const callback_type& callback) 29 | { 30 | m_event_fd = eventfd(0,EFD_NONBLOCK) ; 31 | if(m_event_fd < 0) return -2 ; 32 | reactor.add_handler(m_event_fd,this,base_reactor::EVENT_READ) ; 33 | m_reactor = &reactor ; 34 | m_callback = callback ; 35 | return 0 ; 36 | 37 | } 38 | 39 | void eventfd_handler::fini() 40 | { 41 | if(m_reactor) m_reactor->del_handler(m_event_fd) ; 42 | 43 | if(m_event_fd >0) 44 | { 45 | close(m_event_fd) ; 46 | m_event_fd = -1 ; 47 | } 48 | } 49 | 50 | 51 | int eventfd_handler::notify(int64_t v) 52 | { 53 | return write(m_event_fd,(char*)&v,sizeof(v)) ; 54 | } 55 | 56 | 57 | 58 | 59 | void eventfd_handler::on_read(int fd) 60 | { 61 | uint64_t v ; 62 | read(m_event_fd,&v,sizeof(v)) ; 63 | m_callback(v) ; 64 | } 65 | 66 | void eventfd_handler::on_write(int fd) 67 | { 68 | } 69 | 70 | void eventfd_handler::on_error(int fd) 71 | { 72 | 73 | } 74 | 75 | 76 | } 77 | 78 | 79 | -------------------------------------------------------------------------------- /framework/eventfd_handler.h: -------------------------------------------------------------------------------- 1 | /** 2 | * eventfd_handler.h 3 | * Author : lixingyi (lxyfirst@163.com) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #include "io_handler.h" 11 | 12 | namespace framework 13 | { 14 | 15 | class base_reactor ; 16 | 17 | /** 18 | * @brief eventfd handler for event notification 19 | */ 20 | class eventfd_handler : public io_handler 21 | { 22 | public: 23 | typedef std::tr1::function callback_type ; 24 | public: 25 | eventfd_handler() ; 26 | virtual ~eventfd_handler() ; 27 | 28 | int init(base_reactor& reactor,const callback_type& callback) ; 29 | 30 | void fini() ; 31 | 32 | 33 | int notify(int64_t count=1) ; 34 | 35 | 36 | protected: 37 | void on_read(int fd) ; 38 | void on_write(int fd) ; 39 | void on_error(int fd) ; 40 | private: 41 | callback_type m_callback ; 42 | base_reactor* m_reactor ; 43 | int m_event_fd ; 44 | } ; 45 | 46 | } 47 | 48 | 49 | -------------------------------------------------------------------------------- /framework/fsm_manager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * fsm_manager.cpp 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | 8 | #include 9 | #include "fsm_manager.h" 10 | 11 | namespace framework 12 | { 13 | 14 | fsm_manager::fsm_manager() 15 | { 16 | m_seq = 0 ; 17 | //m_container.set_empty_key(-1); 18 | //m_container.set_deleted_key(-2); 19 | } 20 | 21 | 22 | fsm_manager::~fsm_manager() 23 | { 24 | 25 | } 26 | 27 | void fsm_manager::clear() 28 | { 29 | for(auto& pair: m_container) 30 | { 31 | free_fsm(pair.second) ; 32 | } 33 | 34 | m_container.clear() ; 35 | } 36 | 37 | base_fsm* fsm_manager::get_fsm(int fsm_id) 38 | { 39 | fsm_container::iterator it = m_container.find(fsm_id) ; 40 | if(it != m_container.end() ) return it->second ; 41 | 42 | return NULL ; 43 | } 44 | 45 | 46 | base_fsm* fsm_manager::create_fsm(int fsm_type) 47 | { 48 | base_fsm* object = alloc_fsm(fsm_type) ; 49 | if(object == NULL) return NULL ; 50 | 51 | m_seq = (m_seq + 1) & FSM_ID_MASK ; 52 | object->m_id = m_seq ; 53 | 54 | m_container[object->m_id] = object ; 55 | 56 | return object ; 57 | } 58 | 59 | void fsm_manager::destroy_fsm(base_fsm* object) 60 | { 61 | destroy_fsm(object->m_id) ; 62 | } 63 | 64 | void fsm_manager::destroy_fsm(int fsm_id) 65 | { 66 | fsm_container::iterator it = m_container.find(fsm_id) ; 67 | if(it != m_container.end() ) 68 | { 69 | base_fsm* fsm = it->second ; 70 | m_container.erase(it) ; 71 | free_fsm(fsm) ; 72 | } 73 | } 74 | 75 | 76 | } 77 | -------------------------------------------------------------------------------- /framework/fsm_manager.h: -------------------------------------------------------------------------------- 1 | /** 2 | * fsm_manager.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | namespace framework 12 | { 13 | 14 | class fsm_manager ; 15 | 16 | /** 17 | * @brief abstract class for finite state machine 18 | */ 19 | class base_fsm 20 | { 21 | friend class fsm_manager ; 22 | public: 23 | base_fsm():m_id(0) { } ; 24 | virtual ~base_fsm() { } ; 25 | 26 | /** 27 | * @brief fsm entry , callback implemented by concrete class 28 | * @param [in] fsm manager 29 | * @param [in] event type 30 | * @param [in] arg 31 | * 32 | */ 33 | virtual int enter(fsm_manager* fm , int event_type , void* arg) = 0 ; 34 | 35 | public: 36 | /** 37 | * @brief get fsm id assigned by fsm manager 38 | */ 39 | int get_id() const { return m_id ; } ; 40 | 41 | private: 42 | int m_id ; 43 | }; 44 | 45 | /** 46 | * @brief finite state machine manager 47 | */ 48 | class fsm_manager 49 | { 50 | public: 51 | typedef std::tr1::unordered_map fsm_container ; 52 | enum 53 | { 54 | FSM_ID_MASK = 0xfffffff , 55 | }; 56 | public: 57 | fsm_manager() ; 58 | virtual ~fsm_manager() ; 59 | 60 | /** 61 | * @brief create fsm object by type which owned by fsm_manager 62 | * @param [in] fsm type 63 | * @return fsm object created , NULL on failed 64 | */ 65 | base_fsm* create_fsm(int fsm_type) ; 66 | 67 | /** 68 | * @brief destroy fsm 69 | * @param [in] object to be destroyed 70 | */ 71 | void destroy_fsm(base_fsm* object) ; 72 | void destroy_fsm(int fsm_id) ; 73 | 74 | /** 75 | *@brief get fsm object by fsm_id 76 | *@param [in] fsm id 77 | *@return fsm object 78 | */ 79 | base_fsm* get_fsm(int fsm_id) ; 80 | 81 | /** 82 | * @brief clean up all fsm object it hold 83 | */ 84 | void clear() ; 85 | 86 | /** 87 | * @brief get fsm count 88 | */ 89 | int size() { return m_container.size() ; } ; 90 | 91 | protected: 92 | /** 93 | * @brief alloc fsm memory, implemented by concrete class 94 | * @return fsm object pointer 95 | */ 96 | virtual base_fsm* alloc_fsm(int type) = 0 ; 97 | 98 | /** 99 | * @brief free fsm memory, implemented by concrete class 100 | */ 101 | virtual void free_fsm(base_fsm* object) = 0 ; 102 | 103 | private: 104 | fsm_manager(const fsm_manager&) ; 105 | fsm_manager& operator=(const fsm_manager&) ; 106 | 107 | private: 108 | fsm_container m_container ; 109 | int m_seq ; 110 | }; 111 | 112 | 113 | } 114 | 115 | -------------------------------------------------------------------------------- /framework/io_handler.h: -------------------------------------------------------------------------------- 1 | /** 2 | * io_handler.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | namespace framework 10 | { 11 | 12 | enum io_error_type 13 | { 14 | ERROR_TYPE_NONE = 0 , 15 | ERROR_TYPE_SYSTEM = 1 , 16 | ERROR_TYPE_MEMORY = 2 , 17 | ERROR_TYPE_REQUEST = 3 , 18 | ERROR_TYPE_TIMEOUT = 4 , 19 | ERROR_TYPE_PEER_CLOSE = 5 , 20 | ERROR_TYPE_ACTIVE_CLOSE = 6 , 21 | }; 22 | 23 | 24 | /** 25 | * @brief interface for event driven handler 26 | */ 27 | class io_handler 28 | { 29 | public: 30 | io_handler(){ } ; 31 | virtual ~io_handler() { } ; 32 | 33 | 34 | public : 35 | 36 | /** 37 | * @brief error events callback , implemented by concrete class 38 | */ 39 | virtual void on_error(int fd) = 0 ; 40 | 41 | 42 | /** 43 | * @brief read events callback , implemented by concrete class 44 | */ 45 | virtual void on_read(int fd) = 0 ; 46 | 47 | 48 | /** 49 | * @brief write events callback , implemented by concrete class 50 | */ 51 | virtual void on_write(int fd) = 0 ; 52 | 53 | /* 54 | * @brief handler tag id , implemented by concrete class 55 | */ 56 | virtual int tag_id() const { return 0 ;} ; 57 | private: 58 | io_handler(const io_handler& ) ; 59 | io_handler& operator=(const io_handler&) ; 60 | 61 | 62 | }; 63 | 64 | } 65 | 66 | 67 | -------------------------------------------------------------------------------- /framework/ip_range_container.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ip_range_container.cpp 3 | * Author: lixingyi (lxyfirst@163.com) 4 | */ 5 | 6 | #include 7 | 8 | #include "packet.h" 9 | #include "ip_range_container.h" 10 | 11 | namespace framework 12 | { 13 | 14 | ip_range_container::ip_range_container() 15 | { 16 | // TODO Auto-generated constructor stub 17 | 18 | } 19 | 20 | ip_range_container::~ip_range_container() 21 | { 22 | // TODO Auto-generated destructor stub 23 | } 24 | 25 | 26 | bool ip_range_container::add_ip_mask(const char* str_ip,const char* str_mask) 27 | { 28 | in_addr_t ip = inet_addr(str_ip) ; 29 | in_addr_t mask = inet_addr(str_mask) ; 30 | return add_ip_mask(ip,mask) ; 31 | } 32 | 33 | bool ip_range_container::add_ip_mask(in_addr_t ip,in_addr_t mask) 34 | { 35 | ip = ip & mask ; 36 | return add_ip_range(ip,ip | (~mask) ) ; 37 | 38 | } 39 | 40 | bool ip_range_container::add_ip_range(const char* str_begin_ip,const char* str_end_ip) 41 | { 42 | in_addr_t begin_ip = inet_addr(str_begin_ip) ; 43 | in_addr_t end_ip = inet_addr(str_end_ip) ; 44 | return add_ip_range(begin_ip,end_ip) ; 45 | } 46 | 47 | bool ip_range_container::add_ip_range(in_addr_t begin_ip,in_addr_t end_ip) 48 | { 49 | if(begin_ip == INADDR_NONE || end_ip == INADDR_NONE) 50 | { 51 | return false ; 52 | } 53 | 54 | begin_ip = ntoh_int32(begin_ip) ; 55 | end_ip = ntoh_int32(end_ip) ; 56 | if(begin_ip > end_ip) 57 | { 58 | return false ; 59 | } 60 | 61 | ip_range_t ip_range = { begin_ip , end_ip } ; 62 | if(inner_match(&ip_range)) 63 | { 64 | return false ; 65 | } 66 | 67 | m_ip_list.push_back(ip_range) ; 68 | resort() ; 69 | 70 | return true ; 71 | } 72 | 73 | bool ip_range_container::match(const char* str_ip) const 74 | { 75 | in_addr_t ip = inet_addr(str_ip) ; 76 | return match(ip) ; 77 | } 78 | 79 | bool ip_range_container::match(in_addr_t ip) const 80 | { 81 | ip = ntoh_int32(ip) ; 82 | ip_range_t obj = { ip,ip } ; 83 | return inner_match(&obj) ; 84 | } 85 | 86 | static int cmp_ip_range(const void* a,const void* b) 87 | { 88 | const ip_range_container::ip_range_t* ip_a = (const ip_range_container::ip_range_t*)a ; 89 | const ip_range_container::ip_range_t* ip_b = (const ip_range_container::ip_range_t*)b ; 90 | 91 | if ( ip_a->begin_ip > ip_b->end_ip) return 1 ; 92 | if ( ip_a->end_ip < ip_b->begin_ip) return -1 ; 93 | return 0 ; 94 | } 95 | 96 | 97 | 98 | bool ip_range_container::inner_match(const ip_range_t* obj) const 99 | { 100 | void* result=bsearch(obj,m_ip_list.data(),m_ip_list.size(),sizeof(ip_range_t),cmp_ip_range) ; 101 | return result !=NULL ; 102 | } 103 | 104 | void ip_range_container::resort() 105 | { 106 | qsort(m_ip_list.data(),m_ip_list.size(),sizeof(ip_range_t),cmp_ip_range) ; 107 | } 108 | 109 | 110 | 111 | } /* namespace framework */ 112 | -------------------------------------------------------------------------------- /framework/ip_range_container.h: -------------------------------------------------------------------------------- 1 | /** 2 | * ip_range_container.h 3 | * Author: lixingyi (lxyfirst@163.com) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | 12 | namespace framework 13 | { 14 | 15 | 16 | class ip_range_container 17 | { 18 | public: 19 | struct ip_range_t 20 | { 21 | in_addr_t begin_ip ; 22 | in_addr_t end_ip ; 23 | }; 24 | 25 | public: 26 | ip_range_container(); 27 | virtual ~ip_range_container(); 28 | 29 | bool add_ip_mask(const char* str_ip,const char* str_mask) ; 30 | bool add_ip_mask(in_addr_t ip,in_addr_t mask) ; 31 | 32 | bool add_ip_range(const char* str_begin_ip,const char* str_end_ip) ; 33 | bool add_ip_range(in_addr_t begin_ip,in_addr_t end_ip) ; 34 | 35 | bool match(in_addr_t ip) const ; 36 | bool match(const char* str_ip) const ; 37 | 38 | void clear() { m_ip_list.clear() ; } ; 39 | int size() { return m_ip_list.size() ; } ; 40 | 41 | private: 42 | void resort() ; 43 | bool inner_match(const ip_range_t* obj) const; 44 | 45 | private: 46 | std::vector m_ip_list ; 47 | }; 48 | 49 | } 50 | 51 | -------------------------------------------------------------------------------- /framework/linked_map.h: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * linked_map.h 4 | * 5 | * Author: lixingyi (lxyfirst@163.com) 6 | */ 7 | 8 | #pragma once 9 | 10 | #include 11 | #include 12 | 13 | namespace framework 14 | { 15 | 16 | /** 17 | * @brief hashmap with linked list 18 | */ 19 | template 20 | class linked_map 21 | { 22 | public: 23 | typedef K key_type ; 24 | typedef V value_type ; 25 | 26 | class node_type 27 | { 28 | friend class linked_map ; 29 | public: 30 | value_type& value() { return m_value ;} ; 31 | private: 32 | node_type* m_prev ; 33 | node_type* m_next ; 34 | value_type m_value ; 35 | } ; 36 | 37 | typedef std::pair map_value_type ; 38 | typedef std::tr1::unordered_map node_container ; 39 | typedef typename node_container::iterator iterator ; 40 | typedef typename node_container::const_iterator const_iterator ; 41 | 42 | public: 43 | linked_map() 44 | { 45 | m_head.m_next = m_head.m_prev = &m_head ; 46 | }; 47 | 48 | iterator get_node(const key_type& key,bool touch=false) 49 | { 50 | iterator it = m_container.find(key) ; 51 | if(it != m_container.end() && touch ) 52 | { 53 | list_node_remove(&it->second) ; 54 | list_node_insert(&m_head,&it->second,m_head.m_next) ; 55 | } 56 | 57 | return it ; 58 | } 59 | 60 | void erase_node(iterator it) 61 | { 62 | node_type& node = it->second ; 63 | list_node_remove(&node) ; 64 | m_container.erase(it) ; 65 | } 66 | 67 | 68 | 69 | iterator begin() { return m_container.begin() ; } ; 70 | const_iterator begin() const { return m_container.begin() ; } ; 71 | 72 | int size() const { return m_container.size(); } ; 73 | 74 | iterator end() { return m_container.end() ; } ; 75 | const_iterator end() const { return m_container.end() ; } ; 76 | 77 | value_type* get(const key_type& key,bool touch=false) 78 | { 79 | iterator it = get_node(key,touch) ; 80 | if(it!= m_container.end() ) return &it->second.m_value ; 81 | return NULL ; 82 | } 83 | 84 | value_type* insert(const key_type& key) 85 | { 86 | iterator it = m_container.find(key); 87 | if(it == m_container.end()) 88 | { 89 | node_type& node = m_container[key] ; 90 | list_node_insert(&m_head,&node,m_head.m_next) ; 91 | return &node.m_value ; 92 | } 93 | 94 | return NULL ; 95 | } 96 | 97 | value_type* insert(const key_type& key,const value_type& value) 98 | { 99 | value_type* obj = insert(key) ; 100 | if(obj) *obj = value ; 101 | return obj ; 102 | } 103 | 104 | void erase(const key_type& key) 105 | { 106 | iterator it = m_container.find(key) ; 107 | if(it != m_container.end() ) erase_node(it); 108 | 109 | } 110 | 111 | void clear() 112 | { 113 | m_head.m_next = m_head.m_prev = &m_head ; 114 | m_container.clear() ; 115 | } 116 | 117 | value_type* tail() 118 | { 119 | if(&m_head == m_head.m_prev) return NULL ; 120 | return &m_head.m_prev->m_value ; 121 | } 122 | 123 | value_type* head() 124 | { 125 | if(&m_head == m_head.m_next) return NULL ; 126 | return &m_head.m_next->m_value ; 127 | } 128 | 129 | private: 130 | void list_node_insert(node_type* prev,node_type* curr,node_type* next) 131 | { 132 | prev->m_next = curr ; 133 | 134 | curr->m_prev = prev ; 135 | curr->m_next = next ; 136 | 137 | next->m_prev = curr ; 138 | } 139 | 140 | void list_node_remove(node_type* node) 141 | { 142 | node->m_prev->m_next = node->m_next ; 143 | node->m_next->m_prev = node->m_prev ; 144 | 145 | node->m_next = node->m_prev = NULL ; 146 | } 147 | 148 | private: 149 | node_container m_container ; 150 | node_type m_head ; 151 | 152 | } ; 153 | 154 | } 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /framework/log_thread.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * log_thread.cpp 3 | * Author: lixingyi (lxyfirst@163.com) 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | #include "system_util.h" 10 | #include "network_util.h" 11 | #include "packet.h" 12 | 13 | #include "log_thread.h" 14 | 15 | namespace framework 16 | { 17 | 18 | 19 | log_thread::log_thread():m_notify_fd(0),m_now(0) 20 | { 21 | // TODO Auto-generated constructor stub 22 | 23 | } 24 | 25 | log_thread::~log_thread() 26 | { 27 | // TODO Auto-generated destructor stub 28 | } 29 | 30 | int log_thread::on_init() 31 | { 32 | if(m_reactor.init(2)!=0) error_return(-1,"init reactor failed") ; 33 | 34 | int pipe_fd[2] = {0} ; 35 | if(socketpair(AF_UNIX,SOCK_SEQPACKET,0,pipe_fd)!=0) 36 | { 37 | error_return(-1,"create pipe failed") ; 38 | } 39 | 40 | pipe_handler::callback_type callback = std::bind(&log_thread::on_pipe_message,this,std::placeholders::_1) ; 41 | if(m_handler.init(m_reactor,pipe_fd[1],callback )!=0 ) 42 | { 43 | error_return(-1,"init pipe failed") ; 44 | } 45 | 46 | m_notify_fd = pipe_fd[0] ; 47 | 48 | 49 | return 0; 50 | } 51 | 52 | int log_thread::init(const char* prefix,int log_level) 53 | { 54 | if(m_notify_fd < 1) 55 | { 56 | return m_logger.init(prefix,log_level) ; 57 | } 58 | else 59 | { 60 | int name_size = strlen(prefix) ; 61 | char* buf = new char[name_size +1] ; 62 | if(buf == NULL) return -1 ; 63 | memcpy(buf,prefix,name_size) ; 64 | buf[name_size] = '\0' ; 65 | 66 | packet_info msg = {0} ; 67 | msg.type = (MESSAGE_TYPE_CONFIG << 8) | log_level ; 68 | msg.size = time(0) ; 69 | msg.data = buf ; 70 | 71 | if( write(m_notify_fd,&msg,sizeof(msg)) != sizeof(msg) ) 72 | { 73 | delete[] buf ; 74 | return -2 ; 75 | } 76 | } 77 | 78 | return 0 ; 79 | } 80 | 81 | void log_thread::on_fini() 82 | { 83 | close(m_notify_fd) ; 84 | m_notify_fd = 0 ; 85 | 86 | run_once(); 87 | 88 | m_handler.fini() ; 89 | 90 | m_reactor.fini() ; 91 | } 92 | 93 | void log_thread::on_timeout() 94 | { 95 | //m_logger.prepare() ; 96 | } 97 | 98 | void log_thread::run_once() 99 | { 100 | 101 | int now = time(0) ; 102 | if (now - m_now >= 60) 103 | { 104 | m_now = now; 105 | on_timeout(); 106 | } 107 | 108 | m_reactor.run_once(2000) ; 109 | 110 | } 111 | 112 | void log_thread::on_pipe_message(const packet_info* msg) 113 | { 114 | int msg_type = msg->type >> 8 ; 115 | int log_level = msg->type & 0xFF ; 116 | switch(msg_type) 117 | { 118 | case MESSAGE_TYPE_LOG: 119 | //todo: log time stored in msg->size 120 | m_logger.write_string(log_level,msg->data) ; 121 | delete[] msg->data ; 122 | break ; 123 | 124 | case MESSAGE_TYPE_CONFIG: 125 | m_logger.fini() ; 126 | m_logger.init(msg->data,log_level) ; 127 | delete[] msg->data ; 128 | break ; 129 | 130 | } 131 | 132 | } 133 | 134 | int log_thread::write_format(int ll,const char* fmt,...) 135 | { 136 | if( !is_run() ) return -1 ; 137 | 138 | if ( m_notify_fd < 1 || ll < 0 || ll > m_logger.get_level() ) return -1 ; 139 | 140 | 141 | char* buf = new char[day_roll_logger::MAX_LINE_SIZE] ; 142 | if(buf == NULL) return -1 ; 143 | 144 | const int WRITABLE_SIZE = day_roll_logger::MAX_LINE_SIZE-1 ; 145 | va_list ap ; 146 | va_start(ap, fmt); 147 | int length = vsnprintf(buf,WRITABLE_SIZE,fmt,ap) ; 148 | va_end(ap); 149 | 150 | if(length < 0 ) 151 | { 152 | delete[] buf ; 153 | return -2 ; 154 | } 155 | else if ( length >= WRITABLE_SIZE ) 156 | { 157 | length = WRITABLE_SIZE -1 ; 158 | } 159 | 160 | if( buf[length-1] !='\n') 161 | { 162 | buf[length]= '\n' ; 163 | buf[++length]= '\0' ; 164 | } 165 | 166 | packet_info msg = {0} ; 167 | msg.type = (MESSAGE_TYPE_LOG <<8) | ll ; 168 | msg.size = time(0) ; 169 | msg.data = buf ; 170 | 171 | if( write(m_notify_fd,&msg,sizeof(msg)) != sizeof(msg) ) 172 | { 173 | delete[] buf ; 174 | return -2 ; 175 | } 176 | 177 | return 0 ; 178 | } 179 | 180 | 181 | } 182 | 183 | -------------------------------------------------------------------------------- /framework/log_thread.h: -------------------------------------------------------------------------------- 1 | /** 2 | * log_thread.h 3 | * Author: lixingyi (lxyfirst@163.com) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "poll_reactor.h" 9 | #include "thread.h" 10 | #include "pipe_handler.h" 11 | #include "day_roll_logger.h" 12 | 13 | namespace framework 14 | { 15 | 16 | /** 17 | * @brief logger thread 18 | */ 19 | class log_thread: public simple_thread 20 | { 21 | public: 22 | enum 23 | { 24 | MESSAGE_TYPE_LOG = 1 , 25 | MESSAGE_TYPE_CONFIG =2 , 26 | }; 27 | public: 28 | log_thread(); 29 | virtual ~log_thread(); 30 | 31 | int write_format(int level,const char* fmt,...) ; 32 | 33 | int init(const char* prefix,int log_level) ; 34 | 35 | protected: 36 | virtual int on_init() ; 37 | virtual void on_fini() ; 38 | virtual void run_once() ; 39 | 40 | void on_timeout() ; 41 | 42 | void on_pipe_message(const packet_info* msg); 43 | 44 | private: 45 | poll_reactor m_reactor ; 46 | day_roll_logger m_logger ; 47 | pipe_handler m_handler ; 48 | int m_notify_fd ; 49 | int m_now ; 50 | 51 | }; 52 | 53 | } 54 | 55 | -------------------------------------------------------------------------------- /framework/makefile: -------------------------------------------------------------------------------- 1 | 2 | SRCS=$(wildcard *.cpp) 3 | BIN_SRCS=$(shell grep "int main" -l *.cpp) 4 | LIB_SRCS=$(patsubst $(BIN_SRCS),,$(SRCS)) 5 | 6 | DEPS=$(SRCS:.cpp=.d) 7 | OBJS=$(SRCS:.cpp=.o) 8 | 9 | LIB_OBJS=$(patsubst %.cpp,%.o,$(LIB_SRCS)) 10 | BINS=$(patsubst %.cpp,%,$(BIN_SRCS)) 11 | 12 | LIB_NAME=framework 13 | SO_LIB=$(patsubst %,lib%.so,$(LIB_NAME)) 14 | STATIC_LIB=$(patsubst %,lib%.a,$(LIB_NAME)) 15 | 16 | 17 | CC=clang++ 18 | CFLAGS= -std=c++11 -Wall -D_REENTRANT -D_GNU_SOURCE -fPIC 19 | INC= -I. 20 | 21 | ifeq ($(release), 1) 22 | CFLAGS += -O2 -DNDEBUG 23 | else 24 | CFLAGS += -g -DDEBUG 25 | endif 26 | 27 | all: $(BINS) $(SO_LIB) $(STATIC_LIB) 28 | 29 | $(BINS): % : %.o $(LIB_OBJS) 30 | $(CC) $(CFLAGS) -o $@ $^ 31 | $(SO_LIB): $(LIB_OBJS) 32 | $(CC) $(CFLAGS) -shared -o $@ $^ 33 | $(STATIC_LIB): $(LIB_OBJS) 34 | ar -rcs -o $@ $^ 35 | dist : 36 | rm -f $(DEPS) 37 | clean: 38 | rm -f $(BINS) $(OBJS) $(DEPS) $(SO_LIB) $(STATIC_LIB) 39 | release: clean 40 | @make release=1 41 | 42 | %.d : %.cpp 43 | $(CC) $(CFLAGS) -MT $(subst .cpp,.o,$<) -MM $(INC) $< >$@ 44 | %.o : %.cpp 45 | $(CC) $(CFLAGS) $(INC) -c $< 46 | 47 | -include $(DEPS) 48 | 49 | -------------------------------------------------------------------------------- /framework/member_function_bind.h: -------------------------------------------------------------------------------- 1 | /** 2 | * member_function_bind.h 3 | * Author: lixingyi (lxyfirst@163.com) 4 | */ 5 | 6 | #pragma once 7 | 8 | namespace framework 9 | { 10 | 11 | template 12 | class simple_member_func0 13 | { 14 | private: 15 | typedef R (T::*F)() ; 16 | F m_f ; 17 | T* m_t ; 18 | public: 19 | simple_member_func0(F f,T* t):m_f(f),m_t(t) {} ; 20 | R operator()() 21 | { 22 | return (m_t->*m_f)() ; 23 | } 24 | } ; 25 | 26 | template 27 | class simple_member_func1 28 | { 29 | public: 30 | typedef R (T::*F)(A1) ; 31 | F m_f ; 32 | T* m_t ; 33 | public: 34 | simple_member_func1(F f,T* t):m_f(f),m_t(t) {} ; 35 | R operator()(A1& a1) 36 | { 37 | return (m_t->*m_f)(a1) ; 38 | } 39 | 40 | } ; 41 | 42 | 43 | template 44 | class simple_member_func2 45 | { 46 | private: 47 | typedef R (T::*F)(A1,A2) ; 48 | F m_f ; 49 | T* m_t ; 50 | public: 51 | simple_member_func2(F f,T* t):m_f(f),m_t(t) {} ; 52 | R operator()(A1& a1,A2& a2) 53 | { 54 | return (m_t->*m_f)(a1,a2) ; 55 | } 56 | } ; 57 | 58 | template 59 | class simple_member_func3 60 | { 61 | private: 62 | typedef R (T::*F)(A1,A2,A3) ; 63 | F m_f ; 64 | T* m_t ; 65 | public: 66 | simple_member_func3(F f,T* t):m_f(f),m_t(t) {} ; 67 | R operator()(A1& a1,A2& a2,A3& a3) 68 | { 69 | return (m_t->*m_f)(a1,a2,a3) ; 70 | } 71 | } ; 72 | 73 | template 74 | class simple_member_func4 75 | { 76 | private: 77 | typedef R (T::*F)(A1,A2,A3,A4) ; 78 | F m_f ; 79 | T* m_t ; 80 | public: 81 | simple_member_func4(F f,T* t):m_f(f),m_t(t) {} ; 82 | R operator()(A1& a1,A2& a2,A3& a3,A4& a4) 83 | { 84 | return (m_t->*m_f)(a1,a2,a3,a4) ; 85 | } 86 | } ; 87 | 88 | 89 | template 90 | simple_member_func0 member_function_bind(R (T::*f)(),T* t) 91 | { 92 | return simple_member_func0(f,t) ; 93 | } 94 | 95 | template 96 | simple_member_func1 member_function_bind(R (T::*f)(A1),T* t) 97 | { 98 | return simple_member_func1(f,t) ; 99 | } 100 | 101 | 102 | 103 | template 104 | simple_member_func2 member_function_bind(R (T::*f)(A1,A2),T* t) 105 | { 106 | return simple_member_func2(f,t) ; 107 | } 108 | 109 | 110 | 111 | template 112 | simple_member_func3 member_function_bind(R (T::*f)(A1,A2,A3),T* t) 113 | { 114 | return simple_member_func3(f,t) ; 115 | } 116 | 117 | template 118 | simple_member_func4 member_function_bind(R (T::*f)(A1,A2,A3,A4),T* t) 119 | { 120 | return simple_member_func4(f,t) ; 121 | } 122 | 123 | 124 | } 125 | 126 | -------------------------------------------------------------------------------- /framework/mmap_file.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 4 | * Author : lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "mmap_file.h" 14 | 15 | 16 | namespace framework 17 | { 18 | 19 | void* mmap_append_file::add_mmap_segment(int fd,int64_t offset,int64_t size) 20 | { 21 | if( ftruncate(fd,offset + size )!=0) return NULL ; 22 | void* file_addr = mmap(NULL,size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,offset) ; 23 | if(file_addr == MAP_FAILED ) return NULL ; 24 | return file_addr ; 25 | } 26 | 27 | int64_t mmap_append_file::calc_align_size(int64_t size) 28 | { 29 | 30 | return size - size % MMAP_SEGMENT_SIZE ; 31 | } 32 | 33 | 34 | mmap_append_file::~mmap_append_file() 35 | { 36 | fini() ; 37 | } 38 | 39 | int mmap_append_file::init(const char* file_name,int64_t max_size) 40 | { 41 | if(file_name == NULL || max_size < MMAP_SEGMENT_SIZE ) return -1 ; 42 | int fd = open(file_name,O_CREAT|O_RDWR,0755) ; 43 | if(fd < 1 ) return -2 ; 44 | struct stat st = {0}; 45 | if( fstat(fd, &st)!=0) 46 | { 47 | close(fd) ; 48 | return -1 ; 49 | } 50 | 51 | max_size = calc_align_size(max_size) ; 52 | if( st.st_size > max_size) 53 | { 54 | close(fd) ; 55 | return -1 ; 56 | } 57 | 58 | int64_t align_size = calc_align_size(st.st_size) ; 59 | 60 | void* file_addr = add_mmap_segment(fd,align_size,MMAP_SEGMENT_SIZE) ; 61 | if(file_addr == NULL ) 62 | { 63 | close(fd) ; 64 | return -1 ; 65 | } 66 | 67 | m_fd = fd ; 68 | m_mapped_offset = align_size ; 69 | m_max_size = max_size ; 70 | m_cur_pos = st.st_size % MMAP_SEGMENT_SIZE ; 71 | m_file_addr = file_addr ; 72 | m_flush_pos = m_cur_pos ; 73 | return 0 ; 74 | 75 | 76 | } 77 | 78 | void mmap_append_file::fini() 79 | { 80 | if(m_file_addr) munmap(m_file_addr,MMAP_SEGMENT_SIZE) ; 81 | if(m_fd >0) 82 | { 83 | ftruncate(m_fd,m_mapped_offset + m_cur_pos) ; 84 | close(m_fd) ; 85 | } 86 | 87 | m_fd = -1 ; 88 | m_file_addr = NULL ; 89 | } 90 | 91 | int mmap_append_file::flush() 92 | { 93 | if(m_file_addr == NULL ) return -1 ; 94 | 95 | int ret = msync((char*)m_file_addr + m_flush_pos,m_cur_pos - m_flush_pos,MS_ASYNC) ; 96 | if(ret == 0 ) m_flush_pos = m_cur_pos ; 97 | 98 | return ret ; 99 | } 100 | 101 | int mmap_append_file::write(const char* data,int size) 102 | { 103 | if( size < 1 || size > MMAP_SEGMENT_SIZE || data == NULL ) return -1 ; 104 | if(m_file_addr == NULL ) return -2 ; 105 | 106 | int overflow_size = m_cur_pos + size - MMAP_SEGMENT_SIZE ; 107 | if(overflow_size >0) //overflow 108 | { 109 | if( writable_size() < size ) return -3 ; 110 | 111 | m_mapped_offset += MMAP_SEGMENT_SIZE ; 112 | void* new_file_addr = add_mmap_segment(m_fd,m_mapped_offset,MMAP_SEGMENT_SIZE) ; 113 | if(new_file_addr == NULL ) return -1 ; 114 | 115 | memcpy((char*)m_file_addr + m_cur_pos , data, MMAP_SEGMENT_SIZE - m_cur_pos) ; 116 | memcpy((char*)new_file_addr , data + size - overflow_size , overflow_size) ; 117 | 118 | munmap(m_file_addr,MMAP_SEGMENT_SIZE) ; 119 | m_file_addr = new_file_addr ; 120 | m_cur_pos = overflow_size ; 121 | m_flush_pos = 0 ; 122 | 123 | } 124 | else 125 | { 126 | memcpy((char*)m_file_addr + m_cur_pos,data,size) ; 127 | m_cur_pos += size ; 128 | } 129 | 130 | return 0 ; 131 | } 132 | 133 | mmap_file::~mmap_file() 134 | { 135 | if(m_file_addr) 136 | { 137 | munmap(m_file_addr,m_size) ; 138 | } 139 | } 140 | 141 | int mmap_file::load_file(const char* file_name) 142 | { 143 | int fd = open(file_name,O_RDWR,0) ; 144 | if(fd < 1 ) return -2 ; 145 | struct stat st = {0}; 146 | fstat(fd, &st) ; 147 | if(st.st_size <1) 148 | { 149 | close(fd) ; 150 | return -1 ; 151 | } 152 | 153 | 154 | void* file_addr = mmap(NULL,st.st_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0) ; 155 | close(fd) ; 156 | 157 | if(file_addr == MAP_FAILED ) return -1 ; 158 | 159 | m_file_addr = file_addr ; 160 | m_size = st.st_size ; 161 | m_time = st.st_mtime ; 162 | 163 | return 0 ; 164 | } 165 | 166 | } 167 | 168 | -------------------------------------------------------------------------------- /framework/mmap_file.h: -------------------------------------------------------------------------------- 1 | /** 2 | * mmap_file.h 3 | * Author: lixingyi (lxyfirst@163.com) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | namespace framework 11 | { 12 | 13 | class mmap_append_file 14 | { 15 | public: 16 | enum { MMAP_SEGMENT_SIZE = 0x1 << 24 } ; 17 | 18 | 19 | static void* add_mmap_segment(int fd,int64_t offset,int64_t size) ; 20 | 21 | static int64_t calc_align_size(int64_t size) ; 22 | 23 | public: 24 | mmap_append_file():m_fd(-1),m_cur_pos(0),m_mapped_offset(0), 25 | m_max_size(0),m_file_addr(NULL) ,m_flush_pos(0) 26 | { 27 | }; 28 | 29 | ~mmap_append_file() ; 30 | 31 | 32 | int init(const char* file_name,int64_t max_size) ; 33 | 34 | void fini() ; 35 | 36 | int flush() ; 37 | 38 | int write(const char* data,int size) ; 39 | 40 | int64_t writable_size() const 41 | { 42 | return m_max_size - m_mapped_offset - m_cur_pos ; 43 | } ; 44 | 45 | int64_t total_size() const 46 | { 47 | return m_max_size; 48 | } ; 49 | 50 | private: 51 | int m_fd ; // file descripter 52 | int m_cur_pos ; // memory offset of current segment 53 | int64_t m_mapped_offset ; // file mmap offset 54 | int64_t m_max_size ; // file max size 55 | void* m_file_addr ; 56 | int m_flush_pos ; 57 | } ; 58 | 59 | class mmap_file 60 | { 61 | public: 62 | mmap_file():m_file_addr(NULL),m_size(0) { } ; 63 | ~mmap_file() ; 64 | 65 | int load_file(const char* filename) ; 66 | 67 | int file_size() const { return m_size ; } ; 68 | int file_time() const { return m_time ; } ; 69 | void* file_data() { return m_file_addr ; } ; 70 | 71 | private: 72 | void* m_file_addr ; 73 | int m_size ; 74 | int m_time ; 75 | }; 76 | 77 | } 78 | 79 | 80 | -------------------------------------------------------------------------------- /framework/network_util.h: -------------------------------------------------------------------------------- 1 | /** 2 | * network_util.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace framework 15 | { 16 | 17 | //in_addr_t 18 | typedef struct ::sockaddr_in sa_in_t ; 19 | typedef struct ::sockaddr sa_t ; 20 | typedef struct ::sockaddr_un sa_un_t ; 21 | 22 | 23 | /** 24 | *@brief init address 25 | *@param [out] address 26 | *@param [in] ip string 27 | *@param [in] port 28 | */ 29 | void init_sa_in(sa_in_t* addr,const char* ip,int port) ; 30 | bool equal_sa_in(const sa_in_t* addr1,const sa_in_t* addr2); 31 | void init_sa_un(sa_un_t* addr,const char* sockfile) ; 32 | 33 | const char* addr2str(char* dst,int dst_size,const sa_in_t* addr) ; 34 | 35 | 36 | int set_nonblock(int fd) ; 37 | 38 | void set_socket_buffer(int fd,int val); 39 | 40 | //deprecated , use set_socket_reuse 41 | int set_addr_reuse(int fd) ; 42 | int set_socket_reuse(int fd) ; 43 | 44 | int set_socket_nodelay(int fd) ; 45 | 46 | int set_defer_accept(int fd,int seconds) ; 47 | 48 | int get_socket_error(int fd) ; 49 | 50 | /* 51 | * @return : 0 when event happened 52 | */ 53 | int check_socket_event(int fd,int seconds,bool read_event = true,bool write_event = true); 54 | 55 | //option list: SO_ERROR,SO_REUSEADDR,SO_SNDBUF,SO_RCVBUF,SO_KEEPALIVE,SO_LINGER,SO_TYPE,SO_NREAD,SO_NWRITE 56 | int get_socket_option(int fd,int option_name) ; 57 | int set_socket_option(int fd,int option_name,int option_value) ; 58 | 59 | /** 60 | * @param fd 61 | * @param idle seconds , idle =0 means no keepalive 62 | * @param count 63 | * @param interval seconds 64 | * @return : 0 on success 65 | */ 66 | int set_tcp_keepalive(int fd,int idle=60,int count=2,int interval=10) ; 67 | 68 | 69 | /** socket,bind,listen */ 70 | int create_tcp_service(sa_in_t* addr) ; 71 | int create_udp_service(sa_in_t* addr) ; 72 | 73 | /** socket , connect */ 74 | int create_tcp_client(sa_in_t* remote_addr,int timeout) ; 75 | int create_unix_client(sa_un_t* remote_addr,int timeout) ; 76 | 77 | } 78 | 79 | -------------------------------------------------------------------------------- /framework/object_pool.h: -------------------------------------------------------------------------------- 1 | /** 2 | * object_pool.h 3 | * Author: lixingyi (lxyfirst@163.com) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | namespace framework 12 | { 13 | 14 | template 15 | class object_pool 16 | { 17 | public: 18 | typedef std::set object_container ; 19 | typedef typename object_container::iterator iterator ; 20 | typedef std::list free_container ; 21 | 22 | public: 23 | T* create() 24 | { 25 | T* obj = NULL ; 26 | if(m_free_container.size() >0) 27 | { 28 | obj = m_free_container.back() ; 29 | m_free_container.pop_back() ; 30 | } 31 | else 32 | { 33 | obj = new T ; 34 | } 35 | 36 | if(obj == NULL) return NULL ; 37 | m_object_container.insert(obj) ; 38 | return obj ; 39 | } 40 | 41 | void release(T* obj) 42 | { 43 | m_object_container.erase(obj) ; 44 | 45 | if( m_free_container.size()< m_cache_count) 46 | { 47 | 48 | m_free_container.push_back(obj) ; 49 | } 50 | else 51 | { 52 | delete obj ; 53 | } 54 | } 55 | 56 | void clear() 57 | { 58 | for(auto& item :m_free_container) 59 | { 60 | delete item ; 61 | } 62 | 63 | m_free_container.clear() ; 64 | 65 | for(auto& item :m_object_container) 66 | { 67 | delete item ; 68 | } 69 | 70 | m_object_container.clear() ; 71 | } 72 | 73 | object_pool(int cache_count = 16):m_cache_count(cache_count) {} ; 74 | 75 | ~object_pool() 76 | { 77 | clear() ; 78 | } 79 | 80 | iterator begin() { return m_object_container.begin(); } ; 81 | iterator end() { return m_object_container.end() ; } ; 82 | 83 | private: 84 | object_pool(const object_pool& o) ; 85 | object_pool& operator=(const object_pool& o) ; 86 | 87 | private: 88 | free_container m_free_container ; 89 | object_container m_object_container ; 90 | int m_cache_count ; 91 | }; 92 | 93 | } 94 | 95 | 96 | -------------------------------------------------------------------------------- /framework/object_switcher.h: -------------------------------------------------------------------------------- 1 | /** 2 | * object_switcher.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | namespace framework 10 | { 11 | 12 | /** 13 | * @brief object switcher for safe 14 | */ 15 | template 16 | class object_switcher 17 | { 18 | public: 19 | object_switcher():m_first_active(true){ } ; 20 | 21 | T& active() { return m_first_active ? m_objects[0] : m_objects[1] ; } ; 22 | T& backup() { return m_first_active ? m_objects[1] : m_objects[0] ; } ; 23 | 24 | void switch_object() { m_first_active = !m_first_active ; } ; 25 | 26 | private: 27 | object_switcher(const object_switcher& ) ; 28 | object_switcher& operator=(const object_switcher&) ; 29 | 30 | private: 31 | T m_objects[2] ; 32 | volatile bool m_first_active ; 33 | 34 | }; 35 | 36 | } 37 | 38 | 39 | -------------------------------------------------------------------------------- /framework/observer_manager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * application.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | #include 7 | #include "observer_manager.h" 8 | 9 | namespace framework 10 | { 11 | 12 | void observer_manager::subscribe(int event_id,event_observer* observer) 13 | { 14 | observer_container& oc = m_subscriber_list[event_id] ; 15 | 16 | oc.insert(observer) ; 17 | 18 | } 19 | 20 | void observer_manager::unsubscribe(int event_id,event_observer* observer) 21 | { 22 | subscriber_container::iterator si = m_subscriber_list.find(event_id) ; 23 | if(si != m_subscriber_list.end() ) 24 | { 25 | si->second.erase(observer) ; 26 | } 27 | } 28 | 29 | void observer_manager::publish(int event_id,void* arg) 30 | { 31 | subscriber_container::iterator si = m_subscriber_list.find(event_id) ; 32 | if(si != m_subscriber_list.end() ) 33 | { 34 | /* 35 | class callable 36 | { 37 | public: 38 | callable(int event_id,void* arg):m_event_id(event_id),m_arg(arg) {} ; 39 | void operator()(event_observer* observer) { observer->on_event(m_event_id,m_arg) ; } 40 | private: 41 | int m_event_id ; 42 | void* m_arg ; 43 | } callback(event_id,arg) ; 44 | 45 | std::for_each(si->second.begin(),si->second.end(),callback) ; 46 | */ 47 | 48 | 49 | observer_container& oc = si->second ; 50 | observer_container::iterator it = oc.begin(); 51 | while(it!=oc.end()) 52 | { 53 | event_observer* observer = *it ; 54 | ++it ; 55 | observer->on_event(event_id,arg) ; 56 | } 57 | 58 | } 59 | 60 | } 61 | 62 | } 63 | 64 | -------------------------------------------------------------------------------- /framework/observer_manager.h: -------------------------------------------------------------------------------- 1 | /** 2 | * application.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | namespace framework 13 | { 14 | 15 | class event_observer 16 | { 17 | public: 18 | virtual void on_event(int event_id,void* arg) = 0 ; 19 | } ; 20 | 21 | class observer_manager 22 | { 23 | public: 24 | typedef std::tr1::unordered_set observer_container ; 25 | typedef std::tr1::unordered_map subscriber_container ; 26 | public: 27 | void subscribe(int event_id,event_observer* observer) ; 28 | void unsubscribe(int event_id,event_observer* observer) ; 29 | 30 | void publish(int event_id,void* arg) ; 31 | 32 | private: 33 | subscriber_container m_subscriber_list ; 34 | 35 | } ; 36 | 37 | } 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /framework/packet.h: -------------------------------------------------------------------------------- 1 | /** 2 | * packet.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace framework 14 | { 15 | 16 | # if __BYTE_ORDER == __BIG_ENDIAN 17 | 18 | #define hton_int16(x) (x) 19 | #define hton_int32(x) (x) 20 | #define hton_int64(x) (x) 21 | 22 | #define ntoh_int16(x) (x) 23 | #define ntoh_int32(x) (x) 24 | #define ntoh_int64(x) (x) 25 | 26 | #else 27 | 28 | #define hton_int16(x) bswap_16(x) 29 | #define hton_int32(x) bswap_32(x) 30 | #define hton_int64(x) bswap_64(x) 31 | 32 | #define ntoh_int16(x) bswap_16(x) 33 | #define ntoh_int32(x) bswap_32(x) 34 | #define ntoh_int64(x) bswap_64(x) 35 | 36 | #endif 37 | 38 | class packet 39 | { 40 | public: 41 | virtual ~packet() { } ; 42 | 43 | /* 44 | * @brief get type , implemented by concrete class 45 | * @return object type 46 | */ 47 | virtual int get_type() = 0 ; 48 | 49 | /* 50 | * @brief encode object to buffer , implemented by concrete class 51 | * @param [in] buffer position 52 | * @param [in] max buffer size 53 | * @return actual encoded size , -1 on failure 54 | */ 55 | virtual int encode(char* data,int max_size) = 0 ; 56 | 57 | 58 | /* 59 | * @brief decode object from buffer , implemented by concrete class 60 | * @param [in] buffer position 61 | * @param [in] buffer size 62 | * @return actual decoded size , -1 on failure 63 | */ 64 | virtual int decode(const char* data,int size) = 0 ; 65 | 66 | 67 | /* 68 | * @brief get needed buffer size of encoding , implemented by concrete class 69 | 70 | * @return needed buffer size , -1 on failure 71 | */ 72 | virtual int encode_size() = 0 ; 73 | 74 | 75 | /* 76 | * @brief get needed size of decoding , implemented by concrete class 77 | * @param [in] buffer position 78 | * @param [in] buffer size 79 | * @return actual encoded size , -1 on failure 80 | */ 81 | virtual int decode_size(const char* data,int size) = 0 ; 82 | }; 83 | 84 | struct packet_info 85 | { 86 | int size ; 87 | int type ; 88 | const char* data ; 89 | } ; 90 | 91 | 92 | class packet_factory 93 | { 94 | public: 95 | virtual ~packet_factory() { } ; 96 | 97 | 98 | /* 99 | * @brief get packet info , implemented by concrete class 100 | * @param [in] buffer pointer 101 | * @param [in] buffer size 102 | * @param [out] packet info 103 | * @return 0 on success , -1 on failure 104 | */ 105 | virtual int get_info(const char* data,int size,packet_info* pi) = 0 ; 106 | 107 | 108 | /* 109 | * @brief create packet , implemented by concrete class 110 | * @param [in] packet data 111 | * @param [in] packet info 112 | * @return 0 on success , -1 on failure 113 | */ 114 | virtual packet* create(const char* data,const packet_info* pi) = 0 ; 115 | 116 | }; 117 | 118 | 119 | } 120 | 121 | -------------------------------------------------------------------------------- /framework/packet_processor.h: -------------------------------------------------------------------------------- 1 | /** 2 | * packet_processor.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | namespace framework 10 | { 11 | 12 | class tcp_connection ; 13 | struct packet_info ; 14 | 15 | class packet_processor 16 | { 17 | public: 18 | virtual ~packet_processor() { } ; 19 | 20 | 21 | /* 22 | * @brief get packet info , implemented by concrete class 23 | * @param [in] buffer pointer 24 | * @param [in] buffer size 25 | * @param [out] packet info 26 | * @return 0 on success , -1 on failure 27 | */ 28 | virtual int get_packet_info(tcp_connection* conn,const char* data,int size,packet_info* pi) = 0 ; 29 | 30 | 31 | /* 32 | * @brief process packet callback , implemented by concrete class 33 | * @param [in] connection pointer 34 | * @param [in] packet info 35 | * @return 0 on success , -1 on failure 36 | */ 37 | virtual int process_packet(tcp_connection* conn,const packet_info* pi) = 0 ; 38 | 39 | /* 40 | * @brief connect event callllback , implemented by concrete class 41 | * @param [in] connection pointer 42 | */ 43 | virtual void on_connected(tcp_connection* conn) = 0 ; 44 | 45 | 46 | /* 47 | * @brief disconnect event callllback , implemented by concrete class 48 | * @param [in] connection pointer 49 | * @param [in] io_error_type 50 | */ 51 | virtual void on_closed(tcp_connection* conn,int error_type) = 0 ; 52 | 53 | }; 54 | 55 | } 56 | 57 | -------------------------------------------------------------------------------- /framework/pipe_handler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * pipe_handler.cpp 3 | * Author: lixingyi (lxyfirst@163.com) 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "network_util.h" 12 | #include "packet.h" 13 | 14 | #include "base_reactor.h" 15 | #include "pipe_handler.h" 16 | 17 | namespace framework 18 | { 19 | 20 | pipe_handler::pipe_handler():m_pipe_fd(0) 21 | { 22 | // TODO Auto-generated constructor stub 23 | 24 | } 25 | 26 | pipe_handler::~pipe_handler() 27 | { 28 | fini() ; 29 | } 30 | 31 | int pipe_handler::init(base_reactor& reactor,int pipe_fd,const callback_type& callback) 32 | { 33 | if ( m_pipe_fd > 0) return -1 ; 34 | int sock_type = get_socket_option(pipe_fd,SO_TYPE); 35 | if(sock_type != SOCK_DGRAM && sock_type !=SOCK_SEQPACKET) return -1 ; 36 | 37 | set_nonblock(pipe_fd) ; 38 | 39 | if(reactor.add_handler(pipe_fd,this,base_reactor::EVENT_READ)!=0) 40 | { 41 | return -2 ; 42 | } 43 | 44 | m_callback = callback ; 45 | m_reactor = &reactor ; 46 | m_pipe_fd = pipe_fd ; 47 | 48 | return 0 ; 49 | } 50 | 51 | void pipe_handler::fini() 52 | { 53 | if(m_pipe_fd >0) 54 | { 55 | m_reactor->del_handler(m_pipe_fd) ; 56 | close(m_pipe_fd) ; 57 | m_pipe_fd = -1 ; 58 | } 59 | 60 | } 61 | 62 | void pipe_handler::on_read(int fd) 63 | { 64 | for(;;) 65 | { 66 | packet_info msg ; 67 | int ret = read(fd,&msg,sizeof(msg)) ; 68 | if(ret == sizeof(msg) ) 69 | { 70 | m_callback(&msg) ; 71 | } 72 | else 73 | { 74 | if (errno != EAGAIN && errno != EINTR) 75 | { 76 | on_error(fd) ; 77 | return ; 78 | } 79 | 80 | break ; 81 | } 82 | } 83 | 84 | 85 | } 86 | 87 | void pipe_handler::on_write(int fd) 88 | { 89 | 90 | } 91 | 92 | void pipe_handler::on_error(int fd) 93 | { 94 | close(fd) ; 95 | } 96 | 97 | 98 | int pipe_handler::send_pipe_message(const packet_info* msg) 99 | { 100 | if( write(m_pipe_fd,(void*)msg,sizeof(*msg)) == sizeof(*msg) ) return 0 ; 101 | return -1 ; 102 | } 103 | 104 | 105 | } 106 | 107 | -------------------------------------------------------------------------------- /framework/pipe_handler.h: -------------------------------------------------------------------------------- 1 | /** 2 | * pipe_handler.h 3 | * Author: lixingyi (lxyfirst@163.com) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include "io_handler.h" 11 | 12 | namespace framework 13 | { 14 | 15 | class base_reactor ; 16 | struct packet_info ; 17 | 18 | class pipe_handler : public io_handler 19 | { 20 | public: 21 | typedef std::tr1::function callback_type ; 22 | 23 | public: 24 | pipe_handler() ; 25 | 26 | virtual ~pipe_handler(); 27 | public: 28 | /* 29 | * @return: 0 on success 30 | */ 31 | int init(base_reactor& reactor,int pipe_fd,const callback_type& callback) ; 32 | 33 | void fini() ; 34 | /* 35 | @ @brief send packet_info message to pipe 36 | * @return: 0 on success 37 | */ 38 | int send_pipe_message(const packet_info* msg) ; 39 | 40 | protected: 41 | void on_read(int fd) ; 42 | void on_write(int fd) ; 43 | void on_error(int fd) ; 44 | 45 | private: 46 | callback_type m_callback ; 47 | base_reactor* m_reactor ; 48 | int m_pipe_fd ; 49 | }; 50 | 51 | } 52 | -------------------------------------------------------------------------------- /framework/poll_reactor.h: -------------------------------------------------------------------------------- 1 | /** 2 | * poll_reactor.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include "base_reactor.h" 13 | 14 | namespace framework 15 | { 16 | 17 | class io_handler ; 18 | 19 | class poll_reactor : public base_reactor 20 | { 21 | 22 | public: 23 | 24 | typedef struct 25 | { 26 | struct pollfd event ; 27 | io_handler* handler ; 28 | } poll_data ; 29 | 30 | enum 31 | { 32 | MAX_FD_COUNT = 20480 , 33 | } ; 34 | 35 | poll_reactor(); 36 | ~poll_reactor(); 37 | 38 | public: 39 | /* 40 | * @brief initialize , create epoll fd and alloc memory 41 | * @param [in] max fd count 42 | * @return 0 on success , nagtive on failed 43 | */ 44 | int init(int max_count) ; 45 | 46 | void fini() ; 47 | 48 | public: 49 | int add_handler(int fd , io_handler* handler,int event_type) ; 50 | 51 | int mod_handler(int fd , io_handler* handler ,int event_type ) ; 52 | 53 | void del_handler(int fd ) ; 54 | 55 | io_handler* get_handler(int fd) ; 56 | 57 | int run_once(int msec) ; 58 | 59 | 60 | private: 61 | static int comp_poll_data(const void *m1, const void *m2) ; 62 | poll_data* get_poll_data(int fd) ; 63 | void resort_poll_data() ; 64 | 65 | private: 66 | struct pollfd* m_events ; 67 | poll_data* m_handlers ; 68 | int16_t m_max_count; 69 | int16_t m_cur_count; 70 | int8_t m_prepare_flag ; 71 | 72 | }; 73 | 74 | } 75 | 76 | -------------------------------------------------------------------------------- /framework/queue_handler.h: -------------------------------------------------------------------------------- 1 | /** 2 | * queue_handler.h 3 | * Author : lixingyi (lxyfirst@163.com) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include "io_handler.h" 15 | #include "base_reactor.h" 16 | #include "circular_queue.h" 17 | 18 | namespace framework 19 | { 20 | 21 | /** 22 | * @brief eventfd handler for event notification 23 | */ 24 | template 25 | class queue_handler : public io_handler 26 | { 27 | public: 28 | typedef std::function callback_type ; 29 | public: 30 | queue_handler():m_reactor(NULL),m_event_fd(0) {} ; 31 | virtual ~queue_handler() {fini() ;} ; 32 | 33 | int init(base_reactor& reactor,int queue_size,const callback_type& callback) 34 | { 35 | if(m_event_fd >0) return -1 ; 36 | if(m_queue.init(queue_size) !=0 ) return -1 ; 37 | 38 | m_event_fd = eventfd(0,EFD_NONBLOCK) ; 39 | if(m_event_fd < 0) return -1 ; 40 | reactor.add_handler(m_event_fd,this,base_reactor::EVENT_READ) ; 41 | m_reactor = &reactor ; 42 | m_callback = callback ; 43 | 44 | return 0 ; 45 | 46 | } 47 | 48 | 49 | 50 | void fini() 51 | { 52 | if(m_event_fd >0) 53 | { 54 | m_reactor->del_handler(m_event_fd) ; 55 | close(m_event_fd) ; 56 | m_event_fd = 0 ; 57 | } 58 | 59 | m_queue.fini() ; 60 | 61 | } 62 | 63 | int send(T* msg) 64 | { 65 | m_lock.lock() ; 66 | int ret = m_queue.push(msg); 67 | m_lock.unlock() ; 68 | 69 | if(ret !=0) return -1 ; 70 | 71 | int64_t v =1; 72 | write(m_event_fd,(char*)&v,sizeof(v)) ; 73 | return 0 ; 74 | } 75 | 76 | protected: 77 | void on_read(int fd) 78 | { 79 | int64_t v ; 80 | read(m_event_fd,&v,sizeof(v)) ; 81 | T* msg ; 82 | while( m_queue.pop(msg) == 0 ) 83 | { 84 | m_callback(msg) ; 85 | } 86 | } 87 | void on_write(int fd) {}; 88 | void on_error(int fd) {}; 89 | private: 90 | std::mutex m_lock ; 91 | circular_queue m_queue ; 92 | callback_type m_callback ; 93 | base_reactor* m_reactor ; 94 | int m_event_fd ; 95 | 96 | } ; 97 | 98 | } 99 | 100 | 101 | -------------------------------------------------------------------------------- /framework/string_util.h: -------------------------------------------------------------------------------- 1 | /** 2 | * string_util.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace framework 16 | { 17 | 18 | std::string& int2str(std::string& str,long int value) ; 19 | 20 | int bin2hex(char* hex,const unsigned char* bin,int size) ; 21 | int hex2bin(unsigned char* bin,const char* hex,int size) ; 22 | 23 | inline int base64_encode_size(int len) 24 | { 25 | return (((len + 2) / 3) * 4) ; 26 | } 27 | 28 | inline int base64_decode_size(int len) 29 | { 30 | return (((len + 3) / 4) * 3) ; 31 | } 32 | 33 | int base64_encode(unsigned char* dst,const unsigned char* src,int src_size) ; 34 | int base64_decode(unsigned char* dst,const unsigned char* src,int src_size) ; 35 | 36 | struct md5_context 37 | { 38 | uint64_t bytes; 39 | uint32_t a, b, c, d; 40 | unsigned char buffer[64]; 41 | } ; 42 | 43 | void md5_init(md5_context *ctx); 44 | void md5_update(md5_context *ctx, const void *data, size_t size); 45 | void md5_final(unsigned char result[16], md5_context *ctx); 46 | 47 | void md5(std::string& digest,const void *data, int size); 48 | 49 | int hash(const char* str,int size) ; 50 | 51 | int sql_escape_string(char* buf,int size,const char* data,int data_size) ; 52 | 53 | typedef std::vector string_vector ; 54 | 55 | /* 56 | * @brief split string by seperator 57 | * @return count 58 | */ 59 | int split(string_vector& dst,const char* src,int size,char sep=' ') ; 60 | int split(string_vector& dst,const char* src,int size,const char* sep,bool ignore_empty=true) ; 61 | 62 | 63 | } 64 | 65 | -------------------------------------------------------------------------------- /framework/system_util.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * system_util.cpp 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "system_util.h" 23 | 24 | namespace framework 25 | { 26 | 27 | 28 | int set_thread_title(const char* fmt, ...) 29 | { 30 | char title [16] ={0}; 31 | va_list ap; 32 | va_start(ap, fmt); 33 | vsnprintf (title, sizeof (title) , fmt, ap); 34 | va_end (ap); 35 | 36 | return prctl(PR_SET_NAME,title) ; 37 | 38 | } 39 | void set_process_title(int argc,char* argv[],const char* fmt, ...) 40 | { 41 | char *arg_start = argv[0]; 42 | char *arg_end = argv[argc-1] + strlen(argv[argc-1])+1; 43 | 44 | char title [256] ={0}; 45 | va_list ap; 46 | va_start(ap, fmt); 47 | vsnprintf (title, sizeof (title), fmt, ap); 48 | va_end (ap); 49 | 50 | int i=0; 51 | int tlen = strlen (title) + 1; 52 | if (arg_end - arg_start < tlen && environ[0] == arg_end) 53 | { 54 | char *env_next = environ[0]; 55 | for(i=0; environ[i]!=NULL; i++) 56 | { 57 | if(env_next == environ[i]) 58 | { 59 | env_next = environ[i] + strlen (environ[i]) + 1; 60 | environ[i] = strdup(environ[i]); 61 | } 62 | else 63 | { 64 | break; 65 | } 66 | } 67 | arg_end = env_next; 68 | 69 | } 70 | 71 | i = arg_end - arg_start; 72 | if (tlen <= i) 73 | { 74 | strcpy(arg_start, title); 75 | memset(arg_start + tlen, 0, i - tlen); 76 | } 77 | else 78 | { 79 | stpncpy(arg_start, title, i - 1)[0] = '\0'; 80 | } 81 | } 82 | 83 | int lock_file(const char* filename) 84 | { 85 | int fd = open(filename,O_RDONLY|O_CREAT,0755) ; 86 | if ( fd < 0 ) return -1 ; 87 | if( flock(fd,LOCK_EX|LOCK_NB)!=0 ) return -1; 88 | return fd ; 89 | } 90 | 91 | int set_open_file_limit(int maxsize) 92 | { 93 | if (maxsize < 0) return -1; 94 | struct rlimit limit = {(size_t)maxsize, (size_t)maxsize} ; 95 | return setrlimit(RLIMIT_NOFILE,&limit) ; 96 | } 97 | 98 | int get_open_file_limit() 99 | { 100 | struct rlimit limit = {0} ; 101 | if( getrlimit(RLIMIT_NOFILE,&limit)!=0) return -1 ; 102 | return limit.rlim_max ; 103 | } 104 | 105 | int daemon_init(int nochdir,int noclose) 106 | { 107 | pid_t pid = 0 ; 108 | if( (pid = fork() ) < 0 ) return -1 ; 109 | else if(pid != 0 ) _exit(0) ; 110 | 111 | setsid() ; 112 | umask(0) ; 113 | // Ensure future opens won't allocate controlling TTYs 114 | struct sigaction sa ; 115 | memset(&sa, 0, sizeof(sa)); 116 | sa.sa_handler = SIG_IGN; 117 | sigemptyset(&sa.sa_mask); 118 | if (sigaction(SIGHUP, &sa, NULL) < 0) return -1 ; 119 | 120 | if( (pid = fork() ) < 0 ) return -1 ; 121 | else if(pid != 0 ) _exit(0) ; 122 | 123 | if((!nochdir) && (chdir("/")!=0) ) return -1 ; 124 | 125 | if(!noclose) 126 | { 127 | int fd = open("/dev/null", O_RDWR); 128 | if(fd < 0 ) return -1 ; 129 | dup2(fd,0) ; 130 | dup2(fd,1) ; 131 | dup2(fd,2) ; 132 | close(fd); 133 | } 134 | 135 | return 0 ; 136 | 137 | 138 | } 139 | 140 | int get_uid_by_name(const char* username) 141 | { 142 | struct passwd* pwd = getpwnam(username); 143 | if(pwd == NULL ) return -1 ; 144 | return pwd->pw_uid ; 145 | } 146 | 147 | 148 | int set_uid_by_name(const char* username) 149 | { 150 | int uid = get_uid_by_name(username) ; 151 | if(uid < 0) return -1 ; 152 | 153 | return setuid(uid) ; 154 | 155 | } 156 | 157 | 158 | 159 | 160 | } 161 | 162 | -------------------------------------------------------------------------------- /framework/system_util.h: -------------------------------------------------------------------------------- 1 | /** 2 | * system_util.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | namespace framework 16 | { 17 | 18 | #define error_exit(num,fmt,args...) \ 19 | do{fprintf(stderr,"%ld,%s:%d,%d:%s," fmt "\n",time(NULL),__FILE__,__LINE__,errno,strerror(errno),##args);exit(num);} while(0) 20 | 21 | #define error_return(num,fmt,args...) \ 22 | do{fprintf(stderr,"%ld,%s:%d,%d:%s," fmt "\n",time(NULL),__FILE__,__LINE__,errno,strerror(errno),##args);return(num);} while(0) 23 | 24 | #ifdef NDEBUG 25 | #define debug_format(fmt,args...) 26 | 27 | #else 28 | #define debug_format(fmt,args...) \ 29 | do{fprintf(stdout,"%ld,%s:%d," fmt "\n",time(NULL),__FILE__,__LINE__,##args);}while(0) 30 | 31 | #endif 32 | 33 | int set_open_file_limit(int maxsize) ; 34 | 35 | int get_open_file_limit() ; 36 | 37 | int lock_file(const char* filename) ; 38 | 39 | void set_process_title(int argc,char* argv[],const char* fmt, ...) ; 40 | 41 | int set_thread_title(const char* fmt, ...) ; 42 | 43 | int get_uid_by_name(const char* username) ; 44 | 45 | int set_uid_by_name(const char* username) ; 46 | 47 | int daemon_init(int nochdir,int noclose) ; 48 | } 49 | 50 | -------------------------------------------------------------------------------- /framework/tcp_acceptor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * tcp_acceptor.cpp 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "base_reactor.h" 12 | #include "tcp_acceptor.h" 13 | 14 | namespace framework 15 | { 16 | 17 | tcp_acceptor::tcp_acceptor():m_reactor(NULL),m_fd(-1) 18 | { 19 | // TODO Auto-generated constructor stub 20 | 21 | } 22 | 23 | tcp_acceptor::~tcp_acceptor() 24 | { 25 | fini() ; 26 | } 27 | 28 | int tcp_acceptor::init(base_reactor& reactor,const char* host,int port,const callback_type& callback) 29 | { 30 | if(m_fd >= 0 || host == NULL ) return -1 ; 31 | sa_in_t service_addr ; 32 | init_sa_in(&service_addr,host,port) ; 33 | int sfd = create_tcp_service(&service_addr) ; 34 | if(sfd <0 ) return -2 ; 35 | 36 | if( reactor.add_handler(sfd,this,base_reactor::EVENT_READ)!=0 ) 37 | { 38 | close(sfd) ; 39 | return -3 ; 40 | } 41 | m_reactor = &reactor ; 42 | m_fd = sfd ; 43 | m_callback = callback ; 44 | 45 | return 0 ; 46 | 47 | } 48 | 49 | void tcp_acceptor::fini() 50 | { 51 | if(m_fd >= 0 ) 52 | { 53 | m_reactor->del_handler(m_fd) ; 54 | close(m_fd) ; 55 | m_fd = -1 ; 56 | 57 | } 58 | } 59 | 60 | void tcp_acceptor::on_read(int fd) 61 | { 62 | 63 | 64 | socklen_t addr_len; 65 | sa_in_t caddr = {0}; 66 | addr_len = sizeof(caddr); 67 | 68 | int cfd = 0 ; 69 | for(int i = 0 ; i< MAX_ACCEPT_ONCE ; ++i ) 70 | { 71 | cfd = accept(m_fd,(sa_t*)&caddr,&addr_len) ; 72 | if(cfd >= 0 ) 73 | { 74 | if ( m_callback(cfd,&caddr) != 0 ) close(cfd) ; 75 | } 76 | else 77 | { 78 | if(errno == EAGAIN || errno ==EMFILE || errno ==ENFILE) break ; 79 | else if ( errno == EINTR || errno ==ECONNABORTED ) continue ; 80 | else on_error(m_fd) ; 81 | } 82 | } 83 | 84 | 85 | } 86 | 87 | void tcp_acceptor::on_write(int fd) 88 | { 89 | 90 | } 91 | 92 | void tcp_acceptor::on_error(int fd) 93 | { 94 | fini() ; 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /framework/tcp_acceptor.h: -------------------------------------------------------------------------------- 1 | /** 2 | * tcp_acceptor.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include "io_handler.h" 14 | #include "network_util.h" 15 | 16 | namespace framework 17 | { 18 | 19 | class base_reactor ; 20 | 21 | class tcp_acceptor : public io_handler 22 | { 23 | public: 24 | enum 25 | { 26 | MAX_ACCEPT_ONCE = 32 , 27 | }; 28 | 29 | typedef std::tr1::function callback_type ; 30 | 31 | public: 32 | tcp_acceptor(); 33 | virtual ~tcp_acceptor(); 34 | 35 | /* 36 | * @brief create listen socket and add to reactor 37 | * @return 0 if success 38 | */ 39 | int init(base_reactor& reactor,const char* host,int port,const callback_type& callback) ; 40 | 41 | 42 | void fini() ; 43 | 44 | 45 | int fd() { return m_fd ; } ; 46 | 47 | protected: 48 | virtual void on_read(int fd) ; 49 | virtual void on_write(int fd) ; 50 | virtual void on_error(int fd) ; 51 | 52 | 53 | 54 | protected: 55 | base_reactor* m_reactor ; 56 | callback_type m_callback ; 57 | int m_fd ; 58 | }; 59 | 60 | 61 | } 62 | 63 | -------------------------------------------------------------------------------- /framework/tcp_data_handler.h: -------------------------------------------------------------------------------- 1 | /** 2 | * tcp_data_handler.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "io_handler.h" 10 | #include "network_util.h" 11 | #include "buffer.h" 12 | #include "packet.h" 13 | 14 | namespace framework 15 | { 16 | 17 | class base_reactor ; 18 | 19 | class tcp_data_handler : public io_handler 20 | { 21 | public: 22 | struct connection_id 23 | { 24 | int fd ; 25 | int timestamp ; 26 | 27 | bool operator!=(const connection_id& o) const 28 | { 29 | return ( fd!=o.fd || timestamp != o.timestamp) ; 30 | } 31 | 32 | bool operator==(const connection_id& o) const 33 | { 34 | return ( fd==o.fd && timestamp == o.timestamp) ; 35 | } 36 | 37 | } ; 38 | 39 | enum 40 | { 41 | INIT_RECV_BUF_SIZE = 81920 , 42 | INIT_SEND_BUF_SIZE = 81920 , 43 | INIT_BUF_SIZE = 40960 , 44 | }; 45 | 46 | enum 47 | { 48 | MIN_WRITE_SIZE = 0x1 << 10 , 49 | MAX_WRITE_SIZE = 0x1 << 24 , 50 | }; 51 | 52 | //connection status 53 | enum 54 | { 55 | STATUS_CLOSED = 0 , 56 | STATUS_CONNECTING = 1 , 57 | STATUS_CONNECTED = 2 , 58 | STATUS_CLOSING = 3 , 59 | STATUS_SIZE = 4 , 60 | } ; 61 | 62 | //connection options 63 | enum 64 | { 65 | OPTION_NODELAY = 0x1 , // not implemented 66 | OPTION_READALL = 0x1 << 1 , 67 | } ; 68 | 69 | public: 70 | tcp_data_handler(); 71 | virtual ~tcp_data_handler(); 72 | 73 | 74 | public: 75 | /* 76 | * @brief initialize connection , for active connection 77 | * @param [in] event-driven engine which monitor read/write events 78 | * @param [in] remote address to connect 79 | * @param [in] remote port to connect 80 | * @return 0 on sucess , nagtive value on failure 81 | */ 82 | int init(base_reactor& reactor,const char* host,int port) ; 83 | /* 84 | * @brief initialize connection ,for passive connection 85 | * @param [in] event-driven engine which monitor read/write events 86 | * @param [in] fd for monitor 87 | * @return 0 on sucess , nagtive value on failure 88 | */ 89 | int init(base_reactor& reactor,int fd ) ; 90 | 91 | void detach_reactor() ; 92 | int attach_reactor(base_reactor& reactor) ; 93 | 94 | /* 95 | * @brief clear connection and buffer 96 | * @param [in] release buffer memroy flag 97 | */ 98 | void fini(bool release=false) ; 99 | 100 | /* 101 | * @brief get connection_id 102 | */ 103 | const connection_id& get_id() const { return m_id ; } ; 104 | 105 | base_reactor* get_reactor() { return m_reactor ; } ; 106 | 107 | //int8_t get_status() const { return m_connect_status ; } ; 108 | bool is_connected() const { return m_connect_status == STATUS_CONNECTED;}; 109 | bool is_closed() const { return m_connect_status == STATUS_CLOSED ; } ; 110 | 111 | int8_t get_options() const { return m_options ; } ; 112 | 113 | int get_errno() const { return get_socket_error(m_id.fd) ; } ; 114 | 115 | /* 116 | * @brief send data 117 | * @return 0 on success , -1 on failure 118 | */ 119 | int send(const char* data,int size,int delay_flag) ; 120 | 121 | /* 122 | * @brief send packet 123 | * @return 0 on success , -1 on failure 124 | */ 125 | int send(packet * p,int delay_flag = 0) ; 126 | 127 | /* 128 | * @brief local address 129 | */ 130 | int get_sock_addr(sa_in_t* addr) const ; 131 | 132 | /* 133 | * @brief remote address 134 | */ 135 | int get_remote_addr(sa_in_t* addr) const ; 136 | 137 | int get_remote_addr(char* str_addr,int size) const ; 138 | 139 | void set_option(int option , bool flag) ; 140 | 141 | void set_max_write_size(int max_size) 142 | { 143 | if(max_size < MIN_WRITE_SIZE) max_size = MIN_WRITE_SIZE ; 144 | m_max_write_size = max_size ; 145 | } ; 146 | 147 | protected: 148 | 149 | /* 150 | * @brief called after connection established 151 | */ 152 | virtual void on_connected() { } ; 153 | 154 | /* 155 | * @brief called before connection closed 156 | */ 157 | virtual void on_disconnect(int error_type) {} ; 158 | 159 | /* 160 | * @brief called after connection closed 161 | */ 162 | virtual void on_closed() { } ; 163 | 164 | /* 165 | * @brief get packet info , implemented by concrete class 166 | * @param [in] buffer pointer 167 | * @param [in] buffer size 168 | * @param [out] packet info 169 | * @return 0 on success , -1 on failure 170 | */ 171 | virtual int get_packet_info(const char* data,int size,packet_info* pi) = 0 ; 172 | 173 | /* 174 | * @brief process packet callback , implemented by concrete class 175 | * @param [in] packet info 176 | * @return 0 on success , -1 on failure 177 | */ 178 | virtual int process_packet(const packet_info* pi) = 0 ; 179 | 180 | 181 | private: 182 | virtual void on_read(int fd) ; 183 | virtual void on_write(int fd) ; 184 | virtual void on_error(int fd) ; 185 | 186 | void handle_error(int error_type) ; 187 | void update_status(int status,int error_type = ERROR_TYPE_NONE) ; 188 | void inner_fini(bool release) ; 189 | 190 | private: 191 | buffer m_rbuf ; 192 | buffer m_sbuf ; 193 | connection_id m_id ; 194 | base_reactor* m_reactor ; 195 | int m_max_write_size ; 196 | int8_t m_connect_status ; 197 | int8_t m_options ; 198 | int8_t m_write_flag; 199 | 200 | }; 201 | 202 | 203 | 204 | 205 | } 206 | 207 | -------------------------------------------------------------------------------- /framework/thread.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * thread.cpp 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "thread.h" 11 | 12 | 13 | namespace framework 14 | { 15 | 16 | int simple_thread::start() 17 | { 18 | if ( m_tid != 0 ) return -1 ; 19 | 20 | pthread_attr_t attr; 21 | pthread_attr_init(&attr); 22 | pthread_attr_setstacksize(&attr, 8 << 20 ); 23 | 24 | sigset_t sigmask ; 25 | sigfillset(&sigmask) ; 26 | pthread_sigmask(SIG_BLOCK,&sigmask,NULL) ; 27 | int ret = pthread_create((pthread_t*)&m_tid, &attr, thread_entry, this); 28 | pthread_sigmask(SIG_UNBLOCK,&sigmask,NULL) ; 29 | 30 | pthread_attr_destroy(&attr) ; 31 | 32 | return ret ; 33 | } 34 | 35 | 36 | 37 | void simple_thread::join() 38 | { 39 | if ( m_tid != 0 ) 40 | { 41 | 42 | pthread_join(m_tid,NULL) ; 43 | m_tid = 0 ; 44 | } 45 | 46 | } 47 | 48 | static thread_local simple_thread* cur_thread = NULL ; 49 | void* simple_thread::thread_entry(void* arg) 50 | { 51 | cur_thread = (simple_thread*)arg; 52 | 53 | cur_thread->m_status = STATUS_RUNNING ; 54 | if( cur_thread->on_init() != 0 ) 55 | { 56 | return NULL; 57 | } 58 | 59 | while(cur_thread->m_status == STATUS_RUNNING) 60 | { 61 | cur_thread->run_once() ; 62 | } 63 | 64 | cur_thread->on_fini() ; 65 | 66 | return NULL ; 67 | } 68 | 69 | simple_thread* simple_thread::current_thread() 70 | { 71 | return cur_thread ; 72 | } 73 | 74 | 75 | 76 | } 77 | -------------------------------------------------------------------------------- /framework/thread.h: -------------------------------------------------------------------------------- 1 | /** 2 | * thread.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | namespace framework 12 | { 13 | 14 | class simple_thread 15 | { 16 | public: 17 | enum 18 | { 19 | STATUS_STOPPED = 0 , 20 | STATUS_RUNNING = 1 , 21 | }; 22 | 23 | public: 24 | simple_thread():m_tid(0),m_status(STATUS_STOPPED) { } ; 25 | virtual ~simple_thread() { } ; 26 | /* 27 | * @brief create new thread and run 28 | * @return 0 on success 29 | */ 30 | int start() ; 31 | 32 | /* 33 | * @brief stop thread 34 | */ 35 | inline void stop() { m_status = STATUS_STOPPED ; }; 36 | 37 | /* 38 | * @brief join thread 39 | */ 40 | void join() ; 41 | 42 | /* 43 | * @brief thread id 44 | */ 45 | int64_t id() const { return m_tid ; } ; 46 | 47 | 48 | inline bool is_run() { return m_status == STATUS_RUNNING ; }; 49 | 50 | static simple_thread* current_thread() ; 51 | protected: 52 | /* 53 | * @brief called before run loop 54 | * @return 0 on success 55 | */ 56 | virtual int on_init() { return 0 ; } ; 57 | 58 | /* 59 | * @brief called after run loop 60 | */ 61 | virtual void on_fini() { } ; 62 | 63 | /* 64 | * @brief called every loop 65 | */ 66 | virtual void run_once() = 0 ; 67 | 68 | /* 69 | * @brief thread tag id , implemented by concrete class 70 | */ 71 | virtual int tag_id() { return 0 ; } ; 72 | private: 73 | static void* thread_entry(void* arg) ; 74 | private: 75 | int64_t m_tid ; 76 | volatile int m_status ; 77 | }; 78 | 79 | } 80 | 81 | -------------------------------------------------------------------------------- /framework/time_util.h: -------------------------------------------------------------------------------- 1 | /** 2 | * time_util.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | enum 18 | { 19 | SECONDS_QUARTER_HOUR = 900, 20 | SECONDS_HALF_HOUR = 1800, 21 | SECONDS_OF_HOUR = 3600, 22 | SECONDS_OF_DAY = 86400 , 23 | SECONDS_OF_WEEK = SECONDS_OF_DAY *7 24 | }; 25 | 26 | extern long timezone; 27 | 28 | namespace framework 29 | { 30 | 31 | 32 | //CPU's timestamp counter. 33 | inline uint64_t rdtsc() 34 | { 35 | uint32_t low, high; 36 | __asm__ volatile ("rdtsc" : "=a" (low), "=d" (high)); 37 | return (uint64_t) high << 32 | low; 38 | } 39 | 40 | // millisecond , clock_gettime need librt 41 | inline int64_t time_ms() 42 | { 43 | #if 0 44 | 45 | struct timeval tv = {0} ; 46 | gettimeofday(&tv,NULL) ; 47 | return tv.tv_sec * 1000 + tv.tv_usec/1000 ; 48 | 49 | #else 50 | 51 | struct timespec tv = {0} ; 52 | clock_gettime(CLOCK_MONOTONIC,&tv) ; 53 | return tv.tv_sec * 1000 + tv.tv_nsec/1000000 ; 54 | 55 | #endif 56 | } 57 | 58 | 59 | 60 | // microsecond 61 | inline int64_t time_us() 62 | { 63 | #if 0 64 | 65 | struct timeval tv = {0} ; 66 | gettimeofday(&tv,NULL) ; 67 | return tv.tv_sec * 1000000 + tv.tv_usec ; 68 | 69 | #else 70 | 71 | struct timespec tv = {0} ; 72 | clock_gettime(CLOCK_MONOTONIC,&tv) ; 73 | return tv.tv_sec * 1000000 + tv.tv_nsec/1000 ; 74 | 75 | #endif 76 | } 77 | 78 | // get tick counter per microsecond , may block 100 milliseconds 79 | inline int64_t get_tsc_us() 80 | { 81 | int64_t begin_tsc = rdtsc() ; 82 | int64_t begin_us = time_us() ; 83 | int64_t tsc_interval = 0 ; 84 | int64_t us_interval = 0 ; 85 | do 86 | { 87 | usleep(100000) ; 88 | tsc_interval = rdtsc() - begin_tsc ; 89 | us_interval = time_us() - begin_us ; 90 | 91 | } while(us_interval < 1 ); //cliff : || us_interval (100000 << 3) ) ; 92 | 93 | return tsc_interval/us_interval ; 94 | } 95 | 96 | inline time_t str2time(const char* buf,const char* fmt) 97 | { 98 | struct tm tmp_tm = {0} ; 99 | 100 | if ( strptime(buf,fmt,&tmp_tm) == NULL ) return 0 ; 101 | return mktime(&tmp_tm) ; 102 | } 103 | 104 | inline int time2str(char* buf,int maxlen ,const char* fmt,time_t t) 105 | { 106 | struct tm tmp_tm; 107 | localtime_r(&t,&tmp_tm) ; 108 | return strftime(buf,maxlen,fmt,&tmp_tm) ; 109 | } 110 | 111 | inline int time2str_utc(char* buf,int maxlen ,const char* fmt,time_t t) 112 | { 113 | struct tm tmp_tm; 114 | gmtime_r(&t,&tmp_tm) ; 115 | return strftime(buf,maxlen,fmt,&tmp_tm) ; 116 | } 117 | 118 | inline time_t day_begin_time(time_t t) 119 | { 120 | struct tm tm_time = {0} ; 121 | localtime_r(&t,&tm_time) ; 122 | tm_time.tm_hour = 0; 123 | tm_time.tm_min = 0; 124 | tm_time.tm_sec = 0; 125 | return mktime(&tm_time) ; 126 | } 127 | 128 | inline time_t cycle_begin_time(time_t t,int cycle_seconds = SECONDS_OF_DAY , bool utc = true) 129 | { 130 | if(utc && timezone == 0 ) tzset() ; 131 | return ( (t - timezone)/cycle_seconds ) * cycle_seconds + timezone ; 132 | 133 | } 134 | 135 | inline bool is_same_cycle(time_t first_t, time_t second_t, int cycle_seconds = SECONDS_OF_DAY) 136 | { 137 | if (timezone == 0) tzset(); 138 | if (cycle_seconds < 1) return true ; 139 | return (first_t - timezone) / cycle_seconds == (second_t - timezone )/ cycle_seconds ; 140 | } 141 | 142 | } 143 | 144 | 145 | -------------------------------------------------------------------------------- /framework/timer_manager.h: -------------------------------------------------------------------------------- 1 | /** 2 | * timer_manager.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | namespace framework 15 | { 16 | 17 | class timer_manager ; 18 | 19 | /* 20 | * @brief basic timer class , doubled linked 21 | */ 22 | class base_timer 23 | { 24 | friend class timer_manager ; 25 | public: 26 | typedef std::function callback_type ; 27 | 28 | public: 29 | base_timer() : m_next(NULL),m_prev(NULL),m_expired(0) { } ; 30 | ~base_timer() { if(m_prev && m_next) base_timer_remove(this);} ; 31 | 32 | /* 33 | * @brief get timer counter 34 | */ 35 | int64_t get_expired() { return m_expired ;} ; 36 | 37 | /* 38 | * @brief set timer counter 39 | * @param [in] timer counter 40 | * @return 0 on sucess 41 | */ 42 | int set_expired(int64_t expired) 43 | { 44 | if(m_next || m_prev) return -1 ; 45 | m_expired = expired; 46 | return -1 ; 47 | } ; 48 | 49 | void set_callback(const callback_type& callback) 50 | { 51 | m_callback = callback ; 52 | } 53 | 54 | template 55 | void set_callback(T* obj,void (T::*callback)(timer_manager* manager) ) 56 | { 57 | m_callback = std::bind(callback,obj,std::placeholders::_1) ; 58 | } 59 | 60 | 61 | bool is_running() { return (m_next || m_prev) ; } ; 62 | 63 | protected: 64 | /* 65 | * @brief callback , called when timer expired 66 | */ 67 | void on_timeout(timer_manager* manager) { m_callback(manager); } ; 68 | 69 | private: 70 | static void base_timer_insert(base_timer* prev,base_timer* curr,base_timer* next); 71 | static void base_timer_remove(base_timer* timer); 72 | private: 73 | 74 | base_timer* m_next ; 75 | base_timer* m_prev ; 76 | int64_t m_expired ; 77 | callback_type m_callback ; 78 | } ; 79 | 80 | 81 | class timer_manager 82 | { 83 | public: 84 | 85 | 86 | public: 87 | timer_manager() ; 88 | ~timer_manager(); 89 | 90 | public: 91 | /* 92 | * @brief initialize , alloc memory 93 | * @param [in] time counter begin to run 94 | * @param [in] slot bits 95 | * @return 0 on success 96 | */ 97 | int init(int64_t start_time,int slot_bits) ; 98 | 99 | 100 | void fini() ; 101 | 102 | /* 103 | * @brief insert timer 104 | * @param [in] timer to be inserted 105 | * @return 0 on success 106 | */ 107 | int add_timer(base_timer* timer) ; 108 | 109 | /* 110 | * @brief remove timer 111 | * @param [in] timer 112 | */ 113 | void del_timer(base_timer* timer) ; 114 | 115 | /* 116 | * @brief call by main loop to run expired timers untill now 117 | */ 118 | void run_until(int64_t now) ; 119 | 120 | int64_t get_curr_expired() const { return m_curr_expired ;} ; 121 | 122 | /* 123 | * @brief the latest timer counter to be expired 124 | */ 125 | int64_t get_next_expired() const { return m_next_expired ;} ; 126 | 127 | int32_t get_max_timeout() const { return m_max_expired ; } ; 128 | private: 129 | enum 130 | { 131 | step_slot_min_bits = 3 , 132 | step_slot_max_bits = 20 , 133 | 134 | } ; 135 | private: 136 | timer_manager(const timer_manager& ) ; 137 | timer_manager& operator=(const timer_manager&) ; 138 | 139 | void skip_to_next_expired(int64_t now) ; 140 | void update_next_expired() ; 141 | void shift_high_slot() ; 142 | 143 | private: 144 | base_timer *m_low_array ; 145 | base_timer *m_high_array ; 146 | int64_t m_curr_expired ; 147 | int64_t m_next_expired ; 148 | int8_t m_step_slot_bits ; 149 | int16_t m_step_slot_size ; 150 | int32_t m_step_slot_mask ; 151 | int32_t m_max_expired ; 152 | int32_t m_low_pos ; 153 | int32_t m_high_pos ; 154 | 155 | }; 156 | 157 | } 158 | 159 | -------------------------------------------------------------------------------- /framework/udp_data_handler.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 4 | * Author : lixingyi (lxyfirst@163.com) 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "udp_data_handler.h" 13 | 14 | namespace framework 15 | { 16 | 17 | udp_data_handler::udp_data_handler():m_reactor(NULL),m_fd(-1),m_options(0) 18 | { 19 | } 20 | 21 | udp_data_handler::~udp_data_handler() 22 | { 23 | fini() ; 24 | } 25 | 26 | int udp_data_handler::init(base_reactor& reactor,const char* host,int port) 27 | { 28 | if(m_fd >= 0 || host == NULL ) return -1 ; 29 | sa_in_t service_addr ; 30 | init_sa_in(&service_addr,host,port) ; 31 | int sfd = create_udp_service(&service_addr) ; 32 | if(sfd <0 ) return -2 ; 33 | 34 | set_socket_option(sfd,SO_RCVBUF,MAX_BUF_SIZE * 1024) ; 35 | set_socket_option(sfd,SO_SNDBUF,MAX_BUF_SIZE * 1024) ; 36 | 37 | if( reactor.add_handler(sfd, this, base_reactor::EVENT_READ)!=0 ) 38 | { 39 | close(sfd) ; 40 | return -3 ; 41 | } 42 | 43 | m_reactor = &reactor ; 44 | m_fd = sfd ; 45 | 46 | return 0 ; 47 | 48 | } 49 | 50 | void udp_data_handler::fini() 51 | { 52 | if(m_fd >= 0 ) 53 | { 54 | m_reactor->del_handler(m_fd) ; 55 | close(m_fd) ; 56 | m_fd = -1 ; 57 | 58 | } 59 | } 60 | 61 | void udp_data_handler::handle_error(int error_type) 62 | { 63 | on_event(error_type) ; 64 | } 65 | 66 | void udp_data_handler::on_read(int fd) 67 | { 68 | udp_packet* p = (udp_packet*)m_buf ; 69 | static const int UDP_RECV_SIZE = MAX_BUF_SIZE-sizeof(udp_packet) -1 ; 70 | do 71 | { 72 | socklen_t addrlen = sizeof(p->addr); 73 | p->data_size = recvfrom(fd,p->data,UDP_RECV_SIZE,0,(sa_t*)&p->addr,&addrlen) ; 74 | if(p->data_size <= 0 ) 75 | { 76 | if (errno != EAGAIN && errno != EINTR) 77 | { 78 | handle_error(ERROR_TYPE_SYSTEM) ; 79 | return ; 80 | } 81 | 82 | break ; 83 | } 84 | else 85 | { 86 | p->data[p->data_size] = 0 ; 87 | process_packet(p) ; 88 | } 89 | 90 | }while(m_options & OPTION_READALL) ; 91 | 92 | } 93 | 94 | void udp_data_handler::on_write(int fd) 95 | { 96 | } 97 | 98 | void udp_data_handler::on_error(int fd) 99 | { 100 | handle_error(ERROR_TYPE_SYSTEM) ; 101 | } 102 | 103 | void udp_data_handler::on_event(int type) 104 | { 105 | fini() ; 106 | } 107 | 108 | int udp_data_handler::send(const sa_in_t* to_addr,const char* data,int size) 109 | { 110 | socklen_t addrlen = sizeof(sa_in_t) ; 111 | if( sendto(m_fd,data,size,0,(const sa_t*)to_addr,addrlen)==size) return 0; 112 | return -1 ; 113 | } 114 | 115 | int udp_data_handler::send(const char* host,int port,const char* data,int size) 116 | { 117 | sa_in_t service_addr ; 118 | init_sa_in(&service_addr,host,port) ; 119 | return send(&service_addr,data,size); 120 | } 121 | 122 | int udp_data_handler::send(const sa_in_t* to_addr, packet *p) 123 | { 124 | //static const int UDP_BUF_SIZE = MAX_BUF_SIZE-sizeof(udp_packet) -1 ; 125 | int size = p->encode_size() ; 126 | if(size < 1 || size >sizeof(m_send_buf) ) return -1 ; 127 | 128 | size = p->encode(m_send_buf,sizeof(m_send_buf)) ; 129 | if ( size < 1 ) return -1 ; 130 | 131 | return send(to_addr,m_send_buf,size); 132 | 133 | } 134 | 135 | void udp_data_handler::set_option(int options,bool flag) 136 | { 137 | if(flag) 138 | { 139 | m_options |= options ; 140 | } 141 | else 142 | { 143 | m_options &= ~options ; 144 | } 145 | 146 | } 147 | 148 | 149 | } 150 | 151 | -------------------------------------------------------------------------------- /framework/udp_data_handler.h: -------------------------------------------------------------------------------- 1 | /** 2 | * udp_data_handler.h 3 | * Author : lixingyi (lxyfirst@163.com) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | #include "io_handler.h" 12 | #include "buffer.h" 13 | #include "network_util.h" 14 | #include "base_reactor.h" 15 | #include "packet.h" 16 | 17 | namespace framework 18 | { 19 | 20 | struct udp_packet 21 | { 22 | sa_in_t addr ; 23 | int data_size ; 24 | char data[0] ; 25 | } ; 26 | 27 | class udp_data_handler : public io_handler 28 | { 29 | public: 30 | enum { MAX_BUF_SIZE = 20480}; 31 | enum 32 | { 33 | OPTION_READALL= 0x1 << 1 , 34 | } ; 35 | 36 | public: 37 | udp_data_handler(); 38 | virtual ~udp_data_handler(); 39 | 40 | /* 41 | * @brief create listen socket and add to reactor 42 | * @return 0 if success 43 | */ 44 | int init(base_reactor& reactor,const char* host,int port) ; 45 | 46 | 47 | void fini() ; 48 | 49 | 50 | int fd() { return m_fd ; } ; 51 | 52 | int get_errno() const { return get_socket_error(m_fd) ; } ; 53 | 54 | /* 55 | * @brief send data 56 | * @return 0 on success , -1 on failure 57 | */ 58 | int send(const sa_in_t* to_addr,const char* data,int size) ; 59 | int send(const char* host,int port,const char* data,int size) ; 60 | int send(const sa_in_t* to_addr,packet *p); 61 | 62 | int get_sock_addr(sa_in_t* addr) const ; 63 | 64 | void set_option(int option , bool flag) ; 65 | 66 | int get_options() const { return m_options;} ; 67 | 68 | protected: 69 | 70 | /* 71 | * @brief handle exceptional event , implemented by concrete class 72 | * @param [in] exception type 73 | */ 74 | virtual void on_event(int type); 75 | 76 | virtual int process_packet(const udp_packet* p) = 0 ; 77 | 78 | 79 | protected: 80 | virtual void on_read(int fd) ; 81 | virtual void on_write(int fd) ; 82 | virtual void on_error(int fd) ; 83 | 84 | void handle_error(int error_type) ; 85 | 86 | protected: 87 | base_reactor* m_reactor ; 88 | int m_fd ; 89 | int m_options; 90 | char m_buf[MAX_BUF_SIZE] ; 91 | char m_send_buf[MAX_BUF_SIZE] ; 92 | }; 93 | 94 | } 95 | 96 | 97 | -------------------------------------------------------------------------------- /framework/unix_config.h: -------------------------------------------------------------------------------- 1 | /** 2 | * unix_config.h 3 | * 4 | * Author: lixingyi (lxyfirst@163.com) 5 | */ 6 | 7 | #pragma once 8 | 9 | namespace framework 10 | { 11 | 12 | class unix_config 13 | { 14 | public: 15 | enum 16 | { 17 | BUCKETS_BITS = 10 , 18 | BUCKETS_MASK = ~((~0x0) << BUCKETS_BITS ) , 19 | BUCKETS_SIZE = ( 0x1 << BUCKETS_BITS ) , 20 | MAX_LINE_SIZE = 2048 , 21 | }; 22 | 23 | struct config_node_type 24 | { 25 | config_node_type* next ; 26 | unsigned int hash_value ; 27 | unsigned int key_size ; 28 | char key[0] ; 29 | }; 30 | 31 | public: 32 | const char* get(const char* key,const char* default_value = 0) ; 33 | 34 | int get(const char* key,int default_value) ; 35 | 36 | 37 | int set(const char* key,const char* value) ; 38 | 39 | int set(const char* key,int key_size,const char* value,int value_size) ; 40 | 41 | void remove(const char* key) ; 42 | 43 | int load(const char* file) ; 44 | 45 | int load(const char* data,int size) ; 46 | 47 | int save(const char* file) ; 48 | void dump(int fd) ; 49 | void clear() ; 50 | 51 | public: 52 | unix_config(); 53 | ~unix_config(); 54 | 55 | private: 56 | unix_config(const unix_config&) ; 57 | unix_config& operator=(const unix_config&) ; 58 | 59 | private: 60 | config_node_type* get_node(const char* key,config_node_type** pre_node_return=0) ; 61 | int parse_line(const char* data) ; 62 | unsigned int hash(const char *p) ; 63 | unsigned int bucket(unsigned hash_value) {return hash_value & BUCKETS_MASK ;} ; 64 | private: 65 | config_node_type* m_buckets[BUCKETS_SIZE] ; 66 | 67 | }; 68 | 69 | } 70 | 71 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | 2 | SUBDIRS=framework public queue_server 3 | 4 | all: 5 | make proto -C public 6 | @for DIR in $(SUBDIRS) ; do \ 7 | make all -C $$DIR ; \ 8 | done 9 | 10 | release: 11 | @for DIR in $(SUBDIRS) ; do \ 12 | make release -C $$DIR ; \ 13 | done 14 | 15 | clean: 16 | @for DIR in $(SUBDIRS) ; do \ 17 | make clean -C $$DIR ; \ 18 | done 19 | 20 | install: 21 | @if ! [ -e deploy ] ; then mkdir deploy ; fi 22 | cp -f queue_server/*.bin deploy/ 23 | cp -f queue_server/*.sh deploy/ 24 | cp -f queue_server/*.xml deploy/ 25 | -------------------------------------------------------------------------------- /public/makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | SRCS=$(wildcard *.cpp) 4 | PROTO_SRCS=$(wildcard *.pb.cc) 5 | 6 | DEPS=$(SRCS:.cpp=.d) 7 | OBJS=$(SRCS:.cpp=.o) $(PROTO_SRCS:.cc=.o) 8 | 9 | LIB_OBJS=$(SRCS:.cpp=.o) $(PROTO_SRCS:.cc=.o) 10 | BINS=$(patsubst %.cpp,%,$(BIN_SRCS)) 11 | 12 | LIB_NAME=proto_message 13 | SO_LIB=$(patsubst %,lib%.so,$(LIB_NAME)) 14 | STATIC_LIB=$(patsubst %,lib%.a,$(LIB_NAME)) 15 | 16 | 17 | CC=clang++ 18 | CFLAGS= -std=c++11 -Wall -D_REENTRANT -D_GNU_SOURCE -fPIC 19 | INC= -I. -I.. 20 | 21 | ifeq ($(release), 1) 22 | CFLAGS += -O2 -DNDEBUG 23 | else 24 | CFLAGS += -g -DDEBUG 25 | endif 26 | 27 | all: $(BINS) $(SO_LIB) $(STATIC_LIB) 28 | 29 | $(BINS): % : %.o $(LIB_OBJS) 30 | $(CC) $(CFLAGS) -o $@ $^ 31 | $(SO_LIB): $(LIB_OBJS) 32 | $(CC) $(CFLAGS) -shared -o $@ $^ 33 | $(STATIC_LIB): $(LIB_OBJS) 34 | ar -crs $@ $^ 35 | dist : 36 | rm -f $(DEPS) 37 | clean: 38 | rm -f $(BINS) $(OBJS) $(DEPS) $(SO_LIB) $(STATIC_LIB) 39 | release: clean 40 | @make release=1 41 | 42 | %.d : %.cpp 43 | $(CC) $(CFLAGS) -MT $(subst .cpp,.o,$<) -MM $(INC) $< >$@ 44 | %.o : %.cpp 45 | $(CC) $(CFLAGS) $(INC) -c $< 46 | %.pb.o : %.pb.cc 47 | $(CC) $(CFLAGS) $(INC) -c $< 48 | 49 | %.pb.h : %.proto 50 | protoc --cpp_out=. $< 51 | 52 | -include $(DEPS) 53 | 54 | -------------------------------------------------------------------------------- /public/message.h: -------------------------------------------------------------------------------- 1 | /* 2 | * message.h 3 | * Desc : message definition 4 | * Author: lxyfirst@163.com 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "template_packet.h" 10 | #include "system.pb.h" 11 | 12 | 13 | 14 | // message definition: msgid + head + body 15 | // msgid : module (1 byte) + type (1 byte) 16 | 17 | //system message 18 | typedef TemplatePacket SSRegisterRequest; 19 | typedef TemplatePacket SSRegisterResponse; 20 | 21 | typedef TemplatePacket SSStatusRequest; 22 | typedef TemplatePacket SSStatusResponse; 23 | 24 | 25 | typedef TemplatePacket SSVoteRequest ; 26 | typedef TemplatePacket SSVoteResponse ; 27 | 28 | typedef TemplatePacket SSVoteNotify; 29 | 30 | typedef TemplatePacket SSSyncQueueRequest ; 31 | typedef TemplatePacket SSSyncQueueResponse ; 32 | 33 | typedef TemplatePacket SSForwardRequest ; 34 | typedef TemplatePacket SSForwardResponse ; 35 | 36 | -------------------------------------------------------------------------------- /public/server_handler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * server_handler.cpp 3 | * Author: lixingyi 4 | */ 5 | 6 | #include "public/template_packet.h" 7 | 8 | #include "public/message.h" 9 | 10 | #include "server_handler.h" 11 | #include "server_manager.h" 12 | 13 | 14 | using namespace framework ; 15 | 16 | ServerHandler::ServerHandler(ServerManager* owner,int16_t local_id): 17 | m_owner(owner),m_local_server_id(local_id),m_remote_server_id(0),m_last_time(0) 18 | { 19 | //m_timer.set_owner(this) ; 20 | 21 | } 22 | 23 | ServerHandler::~ServerHandler() 24 | { 25 | // TODO Auto-generated destructor stub 26 | } 27 | 28 | int ServerHandler::get_packet_info(const char* data,int size,packet_info* pi) 29 | { 30 | if(size <(int) sizeof(PacketHead)) 31 | { 32 | pi->size = sizeof(PacketHead) ; 33 | } 34 | else 35 | { 36 | pi->size = decode_packet_size(data) ; 37 | pi->type = decode_packet_msg_type(data) ; 38 | pi->data = data ; 39 | } 40 | 41 | return 0 ; 42 | 43 | } 44 | 45 | void ServerHandler::on_closed() 46 | { 47 | 48 | m_owner->free_connection(this) ; 49 | 50 | } 51 | 52 | void ServerHandler::on_disconnect(int error_type) 53 | { 54 | 55 | m_owner->unregister_connection(m_remote_server_id,this) ; 56 | 57 | } 58 | 59 | void ServerHandler::on_connected() 60 | { 61 | framework::set_tcp_keepalive(get_id().fd,HEATBEAT_TIME,2,HEATBEAT_TIME/2) ; 62 | m_remote_server_id = 0 ; 63 | m_last_time = time(0) ; 64 | SSRegisterRequest request ; 65 | request.body.set_node_type(get_node_type(m_local_server_id) ) ; 66 | request.body.set_node_id(get_node_id(m_local_server_id) ) ; 67 | 68 | this->send(&request,0) ; 69 | } 70 | 71 | /* 72 | void ServerHandler::on_timeout(framework::timer_manager* manager) 73 | { 74 | if(m_remote_server_id ==0) fini() ; 75 | } 76 | */ 77 | 78 | int ServerHandler::process_packet(const packet_info* pi) 79 | { 80 | m_last_time = time(0) ; 81 | 82 | switch(pi->type) 83 | { 84 | case SSRegisterRequest::packet_type: 85 | return process_register_request(pi) ; 86 | case SSStatusRequest::packet_type: 87 | return process_status_request(pi) ; 88 | case SSStatusResponse::packet_type: 89 | return 0 ; 90 | default: 91 | return m_owner->on_server_packet(this,pi) ; 92 | } 93 | 94 | return 0 ; 95 | 96 | } 97 | 98 | int ServerHandler::process_register_request(const packet_info* pi) 99 | { 100 | SSRegisterRequest request ; 101 | if(request.decode(pi->data,pi->size)!=pi->size ) return -1 ; 102 | int node_type = request.body.node_type() ; 103 | int node_id = request.body.node_id() ; 104 | 105 | int remote_server_id = get_server_id( (int8_t)node_type,(int8_t)node_id ); 106 | //register success 107 | if( m_owner->register_connection(remote_server_id,this) ==0) 108 | { 109 | m_remote_server_id = remote_server_id ; 110 | return 0 ; 111 | } 112 | 113 | //register failed 114 | return -1 ; 115 | } 116 | 117 | int ServerHandler::process_status_request(const packet_info* pi) 118 | { 119 | SSStatusResponse status_response ; 120 | return this->send(&status_response,0) ; 121 | 122 | } 123 | 124 | void ServerHandler::check_connection() 125 | { 126 | if(!is_connected() ) return ; 127 | 128 | int silence = time(0) - m_last_time ; 129 | if(silence < HEATBEAT_TIME ) 130 | { 131 | return ; 132 | } 133 | else if( silence < HEATBEAT_TIME*2 ) 134 | { 135 | SSStatusRequest request ; 136 | this->send(&request,0) ; 137 | } 138 | else 139 | { 140 | fini() ; 141 | } 142 | 143 | } 144 | -------------------------------------------------------------------------------- /public/server_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * server_handler.h 3 | * Author: lixingyi 4 | */ 5 | 6 | #ifndef SERVER_HANDLER_H_ 7 | #define SERVER_HANDLER_H_ 8 | 9 | #include 10 | #include 11 | 12 | #include "framework/tcp_data_handler.h" 13 | //#include "framework/timer_manager.h" 14 | 15 | 16 | class ServerManager ; 17 | 18 | class ServerHandler: public framework::tcp_data_handler 19 | { 20 | public: 21 | enum { 22 | HEATBEAT_TIME = 10 , 23 | } ; 24 | public: 25 | ServerHandler(ServerManager* owner,int16_t local_id); 26 | virtual ~ServerHandler(); 27 | 28 | int16_t local_server_id() const { return m_local_server_id ; } ; 29 | int16_t remote_server_id() const { return m_remote_server_id ; } ; 30 | 31 | //called every 10 seconds to check connection 32 | void check_connection() ; 33 | //void on_timeout(framework::timer_manager* manager) ; 34 | protected: 35 | int get_packet_info(const char* data,int size,framework::packet_info* pi); 36 | 37 | int process_packet(const framework::packet_info* pi); 38 | 39 | void on_closed(); 40 | 41 | void on_connected() ; 42 | 43 | void on_disconnect(int error_type) ; 44 | 45 | int process_register_request(const framework::packet_info* pi); 46 | int process_status_request(const framework::packet_info* pi); 47 | private: 48 | //framework::template_timer m_timer ; 49 | ServerManager* m_owner ; 50 | int16_t m_local_server_id ; 51 | int16_t m_remote_server_id ; 52 | int m_last_time ; 53 | }; 54 | 55 | #endif /* SERVER_HANDLER_H_ */ 56 | -------------------------------------------------------------------------------- /public/server_manager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * server_manager.h 3 | * 4 | * Created on: Nov 2, 2014 5 | * Author: lxyfirst@163.com 6 | */ 7 | 8 | #pragma once 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "framework/tcp_acceptor.h" 15 | #include "server_handler.h" 16 | 17 | struct ServerInfo 18 | { 19 | char host[24] ; 20 | int port ; 21 | int16_t node_id ; 22 | int16_t node_type ; 23 | }; 24 | 25 | 26 | inline int16_t get_server_id(int8_t node_type,uint8_t node_id) 27 | { 28 | return ((int16_t)node_type << 8) | node_id ; 29 | } 30 | 31 | inline int8_t get_node_id(int16_t server_id) 32 | { 33 | return server_id & 0xFF ; 34 | } 35 | 36 | inline int8_t get_node_type(int16_t server_id) 37 | { 38 | return (server_id >>8) & 0xFF ; 39 | } 40 | 41 | typedef std::map ServerInfoContainer ; 42 | 43 | namespace framework 44 | { 45 | class day_roll_logger ; 46 | class base_reactor ; 47 | } 48 | 49 | 50 | class ServerHandler ; 51 | 52 | class ServerObserver 53 | { 54 | public: 55 | virtual int on_server_packet(ServerHandler* handler,const framework::packet_info* pi) {return 0;}; 56 | 57 | virtual void on_server_opend(int remote_server_id) {}; 58 | 59 | virtual void on_server_closed(int remote_server_id) {}; 60 | }; 61 | 62 | class ServerManager 63 | { 64 | public: 65 | typedef std::tr1::function CallbackType ; 66 | typedef std::map ServerContainer ; 67 | typedef std::set ConnectionContainer ; 68 | public: 69 | ServerManager(); 70 | virtual ~ServerManager(); 71 | 72 | int init(framework::day_roll_logger* logger,framework::base_reactor* reactor,ServerObserver* observer,int16_t local_server_id) ; 73 | int init_acceptor(const char* host,int port) ; 74 | void fini() ; 75 | 76 | /* 77 | * @brief active connect to remote server 78 | * @return 0 on success 79 | */ 80 | int create_connection(const char* host,int port,int remote_server_id) ; 81 | 82 | /* 83 | * @brief active connect to servers if connection not exists 84 | */ 85 | void check_server_connect(int server_type,const ServerInfoContainer& server_list) ; 86 | 87 | /* 88 | * @brief accept remote server connection 89 | * @return 0 on success 90 | */ 91 | int on_new_connection(int fd,framework::sa_in_t* addr) ; 92 | 93 | /* 94 | * @brief register connection to server id 95 | * @return 0 on success 96 | */ 97 | int register_connection(int remote_server_id,ServerHandler* handler) ; 98 | 99 | void unregister_connection(int remote_server_id,ServerHandler* handler) ; 100 | 101 | void check_idle_connection() ; 102 | 103 | /* 104 | * @brief free connection 105 | */ 106 | void free_connection(ServerHandler* handler) ; 107 | 108 | /* 109 | * @brief callback by connection when receive packet 110 | */ 111 | int on_server_packet(ServerHandler* handler,const framework::packet_info* pi) 112 | { 113 | //return m_callback(handler,pi) ; 114 | if(m_observer) return m_observer->on_server_packet(handler,pi) ; 115 | return 0 ; 116 | } 117 | 118 | void on_server_opend(int remote_server_id) 119 | { 120 | if(m_observer) m_observer->on_server_opend(remote_server_id); 121 | } 122 | 123 | void on_server_closed(int remote_server_id) 124 | { 125 | if(m_observer) m_observer->on_server_closed(remote_server_id); 126 | } 127 | 128 | /* 129 | * @brief broadcast packet to servers [low_server_id,high_server_id) 130 | */ 131 | int broadcast(int low_server_id,int high_server_id,framework::packet* p) ; 132 | 133 | 134 | int broadcast(int server_type,framework::packet* p) ; 135 | 136 | /* 137 | * @brief get server connection by server_id 138 | * @return server handler 139 | */ 140 | ServerHandler* get_server(int remote_server_id) 141 | { 142 | ServerContainer::iterator it=m_server_container.find(remote_server_id) ; 143 | if(it!=m_server_container.end()) return it->second ; 144 | return NULL ; 145 | } 146 | 147 | int16_t local_server_id() const { return m_local_server_id ; } ; 148 | 149 | int server_count() const { return m_server_container.size() ; } ; 150 | 151 | private: 152 | ServerContainer m_server_container ; 153 | ConnectionContainer m_conn_container ; 154 | framework::day_roll_logger* m_logger ; 155 | framework::base_reactor* m_reactor ; 156 | framework::tcp_acceptor m_acceptor ; 157 | //CallbackType m_callback ; 158 | ServerObserver* m_observer ; 159 | int16_t m_local_server_id ; 160 | }; 161 | 162 | -------------------------------------------------------------------------------- /public/system.proto: -------------------------------------------------------------------------------- 1 | 2 | syntax = "proto2"; 3 | 4 | enum SystemMessageType 5 | { 6 | SYSTEM_BASE = 256 ; 7 | REGISTER_REQUEST = 257 ; 8 | REGISTER_RESPONSE = 258 ; 9 | STATUS_REQUEST = 259 ; 10 | STATUS_RESPONSE = 260 ; 11 | CONFIG_DATA_REQUEST = 261 ; 12 | CONFIG_DATA_RESPONSE = 262 ; 13 | HTTP_REQUEST = 263 ; 14 | 15 | VOTE_REQUEST = 265 ; // VoteData 16 | VOTE_RESPONSE = 266 ; // VoteResponse 17 | 18 | VOTE_NOTIFY = 267 ; // VoteData 19 | 20 | PUSH_QUEUE_REQUEST = 269 ; 21 | PUSH_QUEUE_RESPONSE = 270 ; 22 | 23 | POP_QUEUE_REQUEST = 271 ; 24 | POP_QUEUE_RESPONSE = 272 ; 25 | 26 | SYNC_QUEUE_REQUEST = 273 ; // SyncQueueRequest 27 | SYNC_QUEUE_RESPONSE = 274 ; // SyncQueueData 28 | 29 | FORWARD_REQUEST = 277 ; //ForwardData 30 | FORWARD_RESPONSE = 278 ; //ForwardData 31 | 32 | BROADCAST_NOTIFY = 500 ; 33 | 34 | } 35 | 36 | enum SystemErrorType 37 | { 38 | EC_SUCCESS = 0 ; 39 | EC_VOTE_FAILED = 257 ; 40 | EC_VOTE_LEADER_EXIST = 258 ; 41 | } 42 | 43 | message RegisterRequest 44 | { 45 | required int32 node_type = 1 [default=0] ; 46 | required int32 node_id = 2 [default=0] ; 47 | 48 | } 49 | 50 | message RegisterResponse 51 | { 52 | required int32 error_code = 1 [default=0] ; 53 | } 54 | 55 | message StatusRequest 56 | { 57 | 58 | } 59 | 60 | message StatusResponse 61 | { 62 | 63 | } 64 | 65 | message VoteData 66 | { 67 | optional int32 vote_id = 1 [default=0]; 68 | optional int32 node_id = 2 [default=0]; 69 | optional int64 trans_id = 3 [default=0]; 70 | optional int32 port = 4 [default=0]; 71 | optional string host = 5 [default=""]; 72 | 73 | } 74 | 75 | message VoteResponse 76 | { 77 | required int32 error_code = 1 [default=0] ; 78 | optional VoteData data = 2 ; 79 | } 80 | 81 | 82 | message SyncQueueRequest 83 | { 84 | required int64 last_trans_id = 1 ; 85 | 86 | } 87 | 88 | 89 | message SyncQueueData 90 | { 91 | required int64 last_trans_id = 8 ; 92 | required int64 trans_id = 1 ; 93 | required string queue = 2 ; 94 | required int32 op_type = 3 ; 95 | required int32 message_id = 4 ; 96 | optional int32 delay = 5 [default=0]; 97 | optional int32 ttl = 6 [default=0]; 98 | optional int32 retry = 7 [default=0]; 99 | optional bytes data = 9 ; 100 | } 101 | 102 | message ForwardData 103 | { 104 | required bytes data = 1 ; 105 | required bytes source = 2 ; 106 | required int32 timestamp = 3 ; 107 | } 108 | -------------------------------------------------------------------------------- /queue_server/async_processor_manager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * async_processor_manager.cpp 3 | * Author: lixingyi 4 | */ 5 | 6 | #include "async_processor_manager.h" 7 | //#include "user_async_processor.h" 8 | #include "queue_server.h" 9 | 10 | using namespace framework ; 11 | 12 | 13 | AsyncProcessorManager::AsyncProcessorManager() 14 | { 15 | // TODO Auto-generated constructor stub 16 | 17 | } 18 | 19 | AsyncProcessorManager::~AsyncProcessorManager() 20 | { 21 | clear() ; 22 | } 23 | 24 | base_fsm* AsyncProcessorManager::alloc_fsm(int fsm_type) 25 | { 26 | 27 | switch(fsm_type) 28 | { 29 | case StartVoteProcessor::TYPE: 30 | return new StartVoteProcessor ; 31 | default: 32 | ; 33 | } 34 | 35 | 36 | return NULL ; 37 | } 38 | 39 | void AsyncProcessorManager::free_fsm(base_fsm* object) 40 | { 41 | delete object ; 42 | } 43 | 44 | MajorityProcessor::MajorityProcessor():m_status(STATUS_INIT),m_wait_count(0),m_success_count(0) 45 | { 46 | 47 | m_timer.set_callback(this,&MajorityProcessor::on_timeout) ; 48 | } 49 | 50 | MajorityProcessor::~MajorityProcessor() 51 | { 52 | 53 | } 54 | 55 | int MajorityProcessor::enter(fsm_manager* fm,int event_type,void* arg) 56 | { 57 | 58 | if(m_status == STATUS_INIT && init(arg)== PROCESSOR_CONTINUE ) 59 | { 60 | m_status = STATUS_WAIT_DATA ; 61 | arg = NULL ; 62 | 63 | get_app().add_timer_after(&m_timer,5000) ; 64 | 65 | if( m_wait_count >0 || m_success_count >0) return 0 ; 66 | 67 | } 68 | 69 | if(m_status == STATUS_WAIT_DATA && process(arg) == PROCESSOR_CONTINUE ) 70 | { 71 | if( m_wait_count >0 && m_success_count > 0) return 0 ; 72 | 73 | m_status = STATUS_WAIT_RESULT ; 74 | arg = NULL ; 75 | } 76 | 77 | if(m_status == STATUS_WAIT_RESULT) 78 | { 79 | on_result(m_success_count == 0) ; 80 | } 81 | 82 | fm->destroy_fsm(this) ; 83 | 84 | return 0 ; 85 | 86 | } 87 | 88 | int MajorityProcessor::batch_request(framework::packet* p) 89 | { 90 | int send_count = get_app().broadcast(p) ; 91 | if(send_count >0) 92 | { 93 | set_wait_count(send_count) ; 94 | set_success_count(get_app().majority_count() ) ; 95 | return PROCESSOR_CONTINUE ; 96 | } 97 | 98 | return PROCESSOR_DONE ; 99 | } 100 | 101 | 102 | void MajorityProcessor::on_timeout(timer_manager* manager) 103 | { 104 | 105 | info_log_format(get_app().logger(),"fsm timeout fsm_id:%d",this->get_id()); 106 | 107 | //process(NULL) ; 108 | on_timeout() ; 109 | 110 | get_app().async_manager().destroy_fsm(this->get_id()) ; 111 | } 112 | 113 | 114 | int StartVoteProcessor::init(void* data) 115 | { 116 | VoteData* body = (VoteData*)data ; 117 | trace_log_format(get_app().logger(),"broadcast vote vote_id:%d node_id:%d",body->vote_id(),body->node_id() ) ; 118 | 119 | request.head.seq = this->get_id() ; 120 | request.head.src_key = request.head.dst_key = body->node_id() ; 121 | request.body.CopyFrom(*body) ; 122 | 123 | return batch_request(&request) ; 124 | 125 | } 126 | 127 | 128 | int StartVoteProcessor::process(void* data) 129 | { 130 | packet_info* pi = (packet_info*)data ; 131 | if(response.decode(pi->data,pi->size)!=pi->size) return PROCESSOR_DONE ; 132 | 133 | trace_log_format(get_app().logger(),"vote response node_id:%d result:%d", 134 | response.head.src_key ,response.body.error_code()) ; 135 | 136 | dec_wait_count() ; 137 | if(response.body.error_code() == EC_SUCCESS ) 138 | { 139 | dec_success_count() ; 140 | } 141 | else if(response.body.error_code() == EC_VOTE_LEADER_EXIST) 142 | { 143 | get_app().set_leader(response.body.data()) ; 144 | return PROCESSOR_DONE; 145 | } 146 | else 147 | { 148 | return PROCESSOR_DONE ; 149 | } 150 | 151 | return PROCESSOR_CONTINUE ; 152 | 153 | } 154 | 155 | 156 | void StartVoteProcessor::on_result(bool success) 157 | { 158 | if(success) 159 | { 160 | info_log_format(get_app().logger(),"vote success") ; 161 | SSVoteNotify notify; 162 | notify.head.seq = this->get_id() ; 163 | notify.body.CopyFrom(request.body) ; 164 | get_app().broadcast(¬ify) ; 165 | get_app().set_leader(request.body) ; 166 | 167 | } 168 | else 169 | { 170 | info_log_format(get_app().logger(),"vote failed") ; 171 | } 172 | 173 | } 174 | 175 | void StartVoteProcessor::on_timeout() 176 | { 177 | info_log_format(get_app().logger(),"vote timeout") ; 178 | } 179 | 180 | StartVoteProcessor::~StartVoteProcessor() 181 | { 182 | get_app().stop_vote() ; 183 | } 184 | 185 | -------------------------------------------------------------------------------- /queue_server/async_processor_manager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * async_processor_manager.h 3 | * Author: lxyfirst@163.com 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "framework/fsm_manager.h" 9 | #include "framework/timer_manager.h" 10 | #include "framework/packet.h" 11 | #include "framework/tcp_data_handler.h" 12 | #include "public/message.h" 13 | 14 | enum 15 | { 16 | STATUS_INIT = 0 , 17 | STATUS_WAIT_DATA = 1 , 18 | STATUS_WAIT_RESULT = 2 , 19 | }; 20 | 21 | enum 22 | { 23 | PROCESSOR_DONE = -1 , 24 | PROCESSOR_CONTINUE = 0 , 25 | }; 26 | 27 | 28 | 29 | class AsyncProcessorManager: public framework::fsm_manager 30 | { 31 | public: 32 | AsyncProcessorManager(); 33 | virtual ~AsyncProcessorManager(); 34 | 35 | protected: 36 | virtual framework::base_fsm* alloc_fsm(int fsm_type); 37 | virtual void free_fsm(framework::base_fsm* object); 38 | }; 39 | 40 | 41 | 42 | class MajorityProcessor : public framework::base_fsm 43 | { 44 | public: 45 | MajorityProcessor() ; 46 | virtual ~MajorityProcessor() ; 47 | 48 | int enter(framework::fsm_manager* fm,int event_type,void* arg); 49 | 50 | void on_timeout(framework::timer_manager* manager) ; 51 | 52 | protected: 53 | void set_wait_count(int count) {m_wait_count = count ; } ; 54 | void set_success_count(int count) { m_success_count = count ; } ; 55 | void dec_wait_count() { --m_wait_count ; } ; 56 | void dec_success_count() { --m_success_count ; } ; 57 | 58 | int batch_request(framework::packet* p) ; 59 | 60 | virtual int init(void* data) =0 ; 61 | virtual int process(void* data) =0 ; 62 | virtual void on_timeout() {} ; 63 | virtual void on_result(bool success) = 0 ; 64 | 65 | protected: 66 | framework::base_timer m_timer ; 67 | int8_t m_status ; 68 | int8_t m_wait_count ; 69 | int8_t m_success_count ; 70 | 71 | 72 | }; 73 | 74 | class ClientAsyncProcessor : public MajorityProcessor 75 | { 76 | public: 77 | virtual ~ClientAsyncProcessor() { } ; 78 | 79 | framework::tcp_data_handler::connection_id conn_id ; 80 | }; 81 | 82 | 83 | class StartVoteProcessor : public ClientAsyncProcessor 84 | { 85 | public: 86 | enum {TYPE = SSVoteRequest::packet_type } ; 87 | ~StartVoteProcessor() ; 88 | protected: 89 | virtual int init(void* data) ; 90 | virtual int process(void* data) ; 91 | virtual void on_timeout() ; 92 | virtual void on_result(bool success) ; 93 | 94 | public: 95 | SSVoteRequest request ; 96 | SSVoteResponse response ; 97 | 98 | }; 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /queue_server/client_tcp_handler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * client_tcp_handler.cpp 3 | * 4 | * Created on: Oct 25, 2015 5 | * Author: lxyfirst@163.com 6 | */ 7 | 8 | #include "framework/string_util.h" 9 | #include "client_tcp_handler.h" 10 | #include "worker_util.h" 11 | #include "queue_processor.h" 12 | #include "public/message.h" 13 | 14 | using namespace framework ; 15 | 16 | 17 | ClientTcpHandler::ClientTcpHandler() 18 | { 19 | 20 | m_idle_timer.set_callback(this,&ClientTcpHandler::on_timeout) ; 21 | 22 | } 23 | 24 | ClientTcpHandler::~ClientTcpHandler() 25 | { 26 | 27 | } 28 | 29 | void ClientTcpHandler::on_timeout(timer_manager* manager) 30 | { 31 | int idle_time = time(0)- m_last_time ; 32 | if(idle_time > IDLE_TIMEOUT ) 33 | { 34 | trace_log_format(get_logger(),"timeout fd:%d",this->get_id().fd) ; 35 | fini() ; 36 | } 37 | else 38 | { 39 | get_worker().add_timer_after(&m_idle_timer,IDLE_TIMEOUT) ; 40 | } 41 | } 42 | 43 | void ClientTcpHandler::on_connected() 44 | { 45 | char addr[32] = {0}; 46 | this->get_remote_addr(addr,sizeof(addr)-1) ; 47 | debug_log_format(get_logger(), 48 | "client connected host:%s fd:%d",addr,this->get_id().fd) ; 49 | 50 | m_last_time = time(0) ; 51 | on_timeout(NULL) ; 52 | 53 | } 54 | 55 | void ClientTcpHandler::send_heartbeat() 56 | { 57 | int now = time(0) ; 58 | if( now - m_last_time >= (IDLE_TIMEOUT >>1) ) 59 | { 60 | m_last_time = now ; 61 | SSStatusRequest heartbeat ; 62 | this->send(&heartbeat,0) ; 63 | } 64 | 65 | 66 | } 67 | 68 | int ClientTcpHandler::on_heartbeat(const framework::packet_info* pi) 69 | { 70 | //SSStatusResponse heartbeat ; 71 | //this->send(&heartbeat,0) ; 72 | return 0 ; 73 | } 74 | 75 | int ClientTcpHandler::get_packet_info(const char* data,int size,framework::packet_info* pi) 76 | { 77 | static const int MAX_SIZE = 40960 ; 78 | if ( data[0] == '{' && size < MAX_SIZE ) //web socket 79 | { 80 | if( data[size-1] == '}') 81 | { 82 | pi->data = data ; 83 | pi->size =size ; 84 | pi->type = JSON_PACKET_TYPE ; 85 | } 86 | else 87 | { 88 | pi->size =size +1; 89 | } 90 | 91 | } 92 | else 93 | { 94 | //server foward binary data 95 | if(size < (int)sizeof(PacketHead)) 96 | { 97 | pi->size = sizeof(PacketHead) ; 98 | } 99 | else 100 | { 101 | pi->size = decode_packet_size(data) ; 102 | pi->type = decode_packet_msg_type(data) ; 103 | pi->data = data ; 104 | } 105 | } 106 | 107 | if( pi->size < 1 || pi->size > MAX_SIZE) return -1 ; 108 | 109 | 110 | return 0 ; 111 | 112 | } 113 | 114 | int ClientTcpHandler::process_packet(const packet_info* pi) 115 | { 116 | m_last_time = time(0) ; 117 | 118 | switch(pi->type) 119 | { 120 | case FORWARD_REQUEST: 121 | return get_worker().process_forward_request(this,pi) ; 122 | case FORWARD_RESPONSE: 123 | return get_worker().process_forward_response(this,pi) ; 124 | case JSON_PACKET_TYPE: 125 | return process_json_request(pi) ; 126 | case STATUS_REQUEST: 127 | return on_heartbeat(pi) ; 128 | case STATUS_RESPONSE : 129 | return 0 ; 130 | } 131 | 132 | return -1 ; 133 | 134 | } 135 | 136 | int ClientTcpHandler::process_json_request(const packet_info* pi) 137 | { 138 | Document request ; 139 | if(json_decode(pi->data,pi->data + pi->size,request)!=0) return -1 ; 140 | char host[16] = {0} ; 141 | this->get_remote_addr(host,sizeof(host)) ; 142 | 143 | int action = json_get_value(request,FIELD_ACTION,0) ; 144 | if(action <= 0 ) return -1 ; 145 | 146 | debug_log_format(get_logger(),"recv host:%s action:%d size:%d",host,action,pi->size) ; 147 | if((!is_leader() ) && action < ACTION_LOCAL_START) 148 | { 149 | if( is_forward_request() ) 150 | { 151 | SourceData source ; 152 | source.is_tcp = 1 ; 153 | source.id = this->get_id(); 154 | return get_worker().forward_to_leader(source,pi->data,pi->size) ; 155 | } 156 | 157 | //cannot forward , return leader info 158 | request.RemoveAllMembers() ; 159 | request.AddMember(FIELD_ACTION,ACTION_GET_LEADER,request.GetAllocator() ); 160 | 161 | } 162 | 163 | if(QueueProcessor::process(request)==0) 164 | { 165 | StringBuffer buffer ; 166 | json_encode(request,buffer) ; 167 | if( this->send(buffer.GetString(),buffer.GetSize(),0 ) !=0 ) return -1 ; 168 | } 169 | 170 | return 0 ; 171 | } 172 | 173 | 174 | void ClientTcpHandler::on_disconnect(int error_type) 175 | { 176 | get_worker().del_timer(&m_idle_timer) ; 177 | 178 | debug_log_format(get_logger(), 179 | "client closed error_type:%d fd:%d",error_type,this->get_id().fd); 180 | } 181 | 182 | void ClientTcpHandler::on_closed() 183 | { 184 | get_worker().on_client_closed(this) ; 185 | 186 | } 187 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /queue_server/client_tcp_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * client_tcp_handler.h 3 | * 4 | * Created on: Oct 25, 2014 5 | * Author: lxyfirst@163.com 6 | */ 7 | 8 | #pragma once 9 | 10 | #include 11 | 12 | #include "framework/tcp_data_handler.h" 13 | #include "framework/timer_manager.h" 14 | 15 | class ClientTcpHandler: public framework::tcp_data_handler 16 | { 17 | public: 18 | ClientTcpHandler(); 19 | virtual ~ClientTcpHandler(); 20 | enum { JSON_PACKET_TYPE = 1 } ; 21 | enum { IDLE_TIMEOUT = 30 }; 22 | public: 23 | 24 | void on_timeout(framework::timer_manager* manager) ; 25 | 26 | void send_heartbeat() ; 27 | protected: 28 | int get_packet_info(const char* data,int size,framework::packet_info* pi) ; 29 | 30 | int process_packet(const framework::packet_info* pi) ; 31 | int process_json_request(const framework::packet_info* pi) ; 32 | 33 | void on_disconnect(int error_type) ; 34 | 35 | void on_closed() ; 36 | 37 | void on_connected() ; 38 | 39 | 40 | int on_heartbeat(const framework::packet_info* pi); 41 | 42 | private: 43 | framework::base_timer m_idle_timer ; 44 | int m_last_time ; 45 | 46 | }; 47 | 48 | -------------------------------------------------------------------------------- /queue_server/client_udp_handler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * client_udp_handler.cpp 3 | * Author: lixingyi 4 | */ 5 | 6 | 7 | 8 | #include "client_udp_handler.h" 9 | #include "worker_util.h" 10 | #include "queue_processor.h" 11 | 12 | ClientUdpHandler::ClientUdpHandler() 13 | { 14 | // TODO Auto-generated constructor stub 15 | 16 | } 17 | 18 | ClientUdpHandler::~ClientUdpHandler() 19 | { 20 | // TODO Auto-generated destructor stub 21 | } 22 | 23 | 24 | 25 | int ClientUdpHandler::process_packet(const udp_packet* p) 26 | { 27 | if(p->data[0] != '{') return 0 ; 28 | 29 | Document request ; 30 | if(json_decode(p->data,p->data + p->data_size,request)!=0) return 0 ; 31 | 32 | char remote_host[16] = {0} ; 33 | framework::addr2str(remote_host,sizeof(remote_host),&p->addr) ; 34 | 35 | int action = json_get_value(request,FIELD_ACTION,0) ; 36 | if(action <= 0 ) return -1 ; 37 | 38 | debug_log_format(get_logger(),"recv host:%s action:%d size:%d",remote_host,action,p->data_size) ; 39 | 40 | if((!is_leader() ) && action < ACTION_LOCAL_START) 41 | { 42 | if( is_forward_request() ) 43 | { 44 | SourceData source ; 45 | source.is_tcp = 0 ; 46 | source.addr = p->addr ; 47 | if(get_worker().forward_to_leader(source,p->data,p->data_size)==0 ) 48 | { 49 | return 0 ; 50 | } 51 | } 52 | 53 | //cannot forward , return leader info 54 | request.RemoveAllMembers() ; 55 | request.AddMember(FIELD_ACTION,ACTION_GET_LEADER,request.GetAllocator() ); 56 | } 57 | 58 | if( QueueProcessor::process(request) ==0) 59 | { 60 | rapidjson::StringBuffer buffer ; 61 | json_encode(request,buffer) ; 62 | this->send(&p->addr,buffer.GetString(),buffer.GetSize() ) ; 63 | } 64 | 65 | return 0 ; 66 | 67 | 68 | } 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /queue_server/client_udp_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * client_udp_handler.h 3 | * Author: lxyfirst@163.com 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "framework/udp_data_handler.h" 9 | 10 | using framework::sa_in_t ; 11 | using framework::udp_packet ; 12 | 13 | 14 | class ClientUdpHandler: public framework::udp_data_handler 15 | { 16 | public: 17 | ClientUdpHandler(); 18 | virtual ~ClientUdpHandler(); 19 | 20 | int process_packet(const udp_packet* p); 21 | 22 | int forward_request(const udp_packet* p) ; 23 | }; 24 | 25 | -------------------------------------------------------------------------------- /queue_server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "log_prefix" : "queue_server" , 3 | "log_level" :5 , 4 | 5 | "node_type" :10 , 6 | "node_id" :1 , 7 | "host" : "127.0.0.1", 8 | "port" : 1111 , 9 | 10 | "queue_size":100000 , 11 | "queue_log_size":100000 , 12 | "queue_data_blocks":10, 13 | "queue_data_dir": "queue_data", 14 | "queue_sync_rate":3000 , 15 | "forward_request" : 0, 16 | 17 | "cluster_node_list" : [ 18 | {"node_id":3 , "host":"127.0.0.1", "port":1103 }, 19 | {"node_id":2 , "host":"127.0.0.1", "port":1102 }, 20 | {"node_id":1 , "host":"127.0.0.1", "port":1101 } 21 | ], 22 | "virtual_queue_list" : [ 23 | {"name":"test" , "queue_list" : ["test1","test2"] } 24 | ] 25 | 26 | } 27 | -------------------------------------------------------------------------------- /queue_server/makefile: -------------------------------------------------------------------------------- 1 | 2 | SRCS=$(wildcard *.cpp) 3 | BIN_SRCS=$(shell grep "IMPLEMENT_MAIN" -l *.cpp) 4 | LIB_SRCS=$(patsubst $(BIN_SRCS),,$(SRCS)) 5 | 6 | DEPS=$(SRCS:.cpp=.d) 7 | OBJS=$(SRCS:.cpp=.o) 8 | 9 | LIB_OBJS=$(patsubst %.cpp,%.o,$(LIB_SRCS)) 10 | BINS=$(patsubst %.cpp,%.bin,$(BIN_SRCS)) 11 | DEP_LIBS= ../framework/libframework.a ../public/libproto_message.a 12 | 13 | LIB_NAME= 14 | SO_LIB=$(patsubst %,lib%.so,$(LIB_NAME)) 15 | STATIC_LIB=$(patsubst %,lib%.a,$(LIB_NAME)) 16 | 17 | APP_VERSION=$(shell git show --format="%H" --quiet) 18 | 19 | 20 | CC=clang++ 21 | CFLAGS= -std=c++11 -Wall -D_REENTRANT -D_GNU_SOURCE -fPIC -DAPP_VERSION=\"$(APP_VERSION)\" 22 | INC= -I. -I../framework -I.. 23 | LDFLAGS=-L/usr/local/lib -lprotobuf -lrt -lpthread -ltcmalloc 24 | 25 | ifeq ($(release), 1) 26 | CFLAGS += -O2 -DNDEBUG 27 | else 28 | CFLAGS += -g -DDEBUG 29 | endif 30 | 31 | all: $(BINS) $(SO_LIB) $(STATIC_LIB) 32 | 33 | $(BINS): %.bin : %.o $(LIB_OBJS) $(DEP_LIBS) 34 | $(CC) -o $@ $^ $(LDFLAGS) 35 | $(SO_LIB): $(LIB_OBJS) 36 | $(CC) $(CFLAGS) -shared -o $@ $^ 37 | $(STATIC_LIB): $(LIB_OBJS) 38 | ar -rcs -o $@ $^ 39 | dist : 40 | rm -f $(DEPS) 41 | clean: 42 | rm -f $(BINS) $(OBJS) $(DEPS) $(SO_LIB) $(STATIC_LIB) 43 | release: clean 44 | @make release=1 45 | 46 | deploy: 47 | cp -f *.json ../deploy/conf/ 48 | cp -f $(BINS) ../deploy/bin/ 49 | 50 | %.d : %.cpp 51 | $(CC) $(CFLAGS) -MT $(subst .cpp,.o,$<) -MM $(INC) $< >$@ 52 | %.o : %.cpp 53 | $(CC) $(CFLAGS) $(INC) -c $< 54 | 55 | -include $(DEPS) 56 | 57 | -------------------------------------------------------------------------------- /queue_server/queue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * queue.h 3 | * Author: lxyfirst@163.com 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using std::string ; 15 | 16 | struct QueueMessage 17 | { 18 | static QueueMessage* Create(int id,int retry,int ttl,int data_size,const char* data); 19 | 20 | static void Destroy(QueueMessage* message); 21 | 22 | int id ; 23 | int ttl ; 24 | int retry ; 25 | int data_size ; 26 | char data[0] ; 27 | }; 28 | 29 | inline int32_t create_message_id(int32_t& current_id) 30 | { 31 | current_id = ( current_id & 0xfffffff ) +1 ; 32 | return current_id ; 33 | } 34 | 35 | typedef std::multimap MessageContainer ; 36 | typedef MessageContainer::value_type MessageValue ; 37 | typedef std::tr1::unordered_map IdContainer ; 38 | 39 | class SyncQueueData ; 40 | 41 | class Queue 42 | { 43 | public: 44 | Queue(const string& name); 45 | virtual ~Queue(); 46 | 47 | const string& name() const { return m_name ; } ; 48 | 49 | int size() const { return m_message_container.size() ; } ; 50 | int max_id() const { return m_seq_id ; } ; 51 | 52 | /* 53 | * @brief 队列消息被延期消费的时间统计 54 | */ 55 | int wait_status() const ; 56 | 57 | /* 58 | * @brief 发布消息 59 | * @param request 消息对象 60 | * @return id or 0 61 | */ 62 | int produce(const string& data,int delay,int ttl,int retry) ; 63 | 64 | /* 65 | * @brief 消费消息 66 | * @param data存储返回的消息对象 67 | * @return id or 0 68 | */ 69 | int consume(string& data); 70 | 71 | /* 72 | * @brief 删除消息 73 | */ 74 | void erase(int msg_id) ; 75 | 76 | void clear() ; 77 | 78 | int update(const SyncQueueData& data) ; 79 | 80 | private: 81 | Queue(const Queue& o) ; 82 | Queue& operator=(const Queue& o); 83 | 84 | QueueMessage* inner_produce(const string& data,int delay,int ttl,int retry,int id) ; 85 | 86 | void inner_erase(int msg_id) ; 87 | 88 | private: 89 | 90 | string m_name ; 91 | MessageContainer m_message_container ; 92 | IdContainer m_id_container ; 93 | int32_t m_seq_id ; 94 | 95 | 96 | }; 97 | 98 | class QueueManager 99 | { 100 | public: 101 | typedef std::tr1::unordered_map QueueContainer ; 102 | typedef QueueContainer::const_iterator iterator ; 103 | public: 104 | bool exist(const string& queue_name) const 105 | { 106 | return m_queue_list.count(queue_name) >0 ; 107 | } 108 | 109 | Queue* get_queue(const string& queue_name) 110 | { 111 | QueueContainer::iterator it = m_queue_list.find(queue_name) ; 112 | if(it == m_queue_list.end()) return NULL ; 113 | return it->second ; 114 | } 115 | 116 | Queue* create_queue(const string& queue_name) ; 117 | 118 | 119 | iterator begin() const { return m_queue_list.begin() ;} ; 120 | iterator end() const { return m_queue_list.end() ; } ; 121 | int size() const { return m_queue_list.size() ; } ; 122 | ~QueueManager() ; 123 | 124 | private: 125 | QueueContainer m_queue_list ; 126 | 127 | }; 128 | 129 | -------------------------------------------------------------------------------- /queue_server/queue_processor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * queue_processor.h 3 | * 4 | * Author: lxyfirst@163.com 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "worker_util.h" 10 | class Queue ; 11 | 12 | enum 13 | { 14 | ACTION_PRODUCE = 1 , 15 | ACTION_CONSUME = 2 , 16 | ACTION_CONFIRM = 3 , 17 | ACTION_MONITOR = 4 , 18 | ACTION_CONFIG = 5 , 19 | ACTION_CLEAR = 6 , 20 | ACTION_LIST = 7 , 21 | ACTION_GET_LEADER = 8 , 22 | ACTION_LOCAL_START = 100, 23 | ACTION_LOCAL_MONITOR = 104, 24 | ACTION_LOCAL_LIST = 107, 25 | 26 | }; 27 | 28 | static const char FIELD_CODE[] = "code" ; 29 | static const char FIELD_REASON[] = "reason" ; 30 | static const char FIELD_DATA[] = "data" ; 31 | static const char FIELD_ACTION[] = "action" ; 32 | static const char FIELD_QUEUE[] = "queue" ; 33 | static const char FIELD_DELAY[] = "delay" ; 34 | static const char FIELD_TTL[] = "ttl" ; // expired time 35 | static const char FIELD_RETRY[] = "retry" ; // retry seconds 36 | static const char FIELD_MSG_ID[] = "msg_id" ; 37 | 38 | class QueueProcessor 39 | { 40 | public: 41 | QueueProcessor(); 42 | virtual ~QueueProcessor(); 43 | static int fill_response(Document& request,int code=0,const char* reason = "") ; 44 | static int process(Document& request) ; 45 | static int process_virtual_produce(Document& request,const std::string& queue_name); 46 | static int process_produce(Document& request,Queue& queue); 47 | static int process_consume(Document& request,Queue& queue); 48 | static int process_confirm(Document& request,Queue& queue); 49 | static int process_monitor(Document& request,Queue& queue); 50 | static int process_config(Document& request,Queue& queue); 51 | static int process_clear(Document& request,Queue& queue); 52 | static int process_list(Document& request,const char* pattern); 53 | static int process_get_leader(Document& request); 54 | static void fill_server_info(Document& server_info); 55 | 56 | static bool is_queue_request(int action) ; 57 | }; 58 | 59 | -------------------------------------------------------------------------------- /queue_server/queue_server.h: -------------------------------------------------------------------------------- 1 | /* 2 | * queue_server.h 3 | * 4 | * Created on: Oct 25, 2014 5 | * Author: lxyfirst@163.com 6 | */ 7 | 8 | #pragma once 9 | 10 | #include 11 | #include 12 | 13 | #include "framework/application.h" 14 | #include "framework/tcp_acceptor.h" 15 | #include "framework/day_roll_logger.h" 16 | #include "framework/object_switcher.h" 17 | #include "public/server_manager.h" 18 | #include "public/template_packet.h" 19 | 20 | #include "async_processor_manager.h" 21 | #include "worker_util.h" 22 | 23 | struct NodeData 24 | { 25 | int8_t node_type ; // node type 26 | int8_t node_id ; // self node id 27 | int8_t leader_id ; // leader node id , 0 means no leader 28 | int8_t vote_status ; 29 | }; 30 | 31 | struct QueueConfig 32 | { 33 | int queue_size ; 34 | int log_size ; 35 | int sync_rate ; 36 | int data_blocks ; 37 | std::string dir ; 38 | }; 39 | 40 | class ClientTcpHandler ; 41 | typedef std::map QueueLogContainer ; 42 | 43 | class QueueServer: public framework::application ,public ServerObserver 44 | { 45 | public: 46 | QueueServer(); 47 | virtual ~QueueServer(); 48 | 49 | enum 50 | { 51 | SYNC_TYPE_PUSH = 0 , // oneshot sync 52 | SYNC_TYPE_PULL = 1 , // continuous sync 53 | }; 54 | 55 | public: 56 | // server event 57 | void on_server_opend(int remote_server_id); 58 | void on_server_closed(int remote_server_id); 59 | int on_server_packet(ServerHandler* handler,const framework::packet_info* pi); 60 | int on_fsm_response(ServerHandler* handler,const framework::packet_info* pi); 61 | int on_other_vote(ServerHandler* handler,const framework::packet_info* pi); 62 | int on_vote_success(ServerHandler* handler,const framework::packet_info* pi); 63 | int on_sync_queue_request(ServerHandler* handler,const framework::packet_info* pi) ; 64 | int on_sync_queue_response(ServerHandler* handler,const framework::packet_info* pi) ; 65 | 66 | framework::day_roll_logger& logger() { return m_logger ; } ; 67 | //queue config 68 | int queue_size() const { return m_queue_config.queue_size ; } ; 69 | int log_size() const { return m_queue_config.log_size ; } ; 70 | 71 | const VoteData& self_vote_data() const { return m_self_vote_info ; } ; 72 | 73 | const VoteData& leader_vote_data() 74 | { 75 | static VoteData empty_data ; 76 | const VoteData& vote_data = m_leader_vote_info.active() ; 77 | if(m_node_info.leader_id <1) return empty_data ; 78 | return vote_data.node_id() == m_node_info.leader_id ? vote_data : empty_data ; 79 | } 80 | 81 | int majority_count() const { return (m_cluster_info.size()) >>1 ; } ; 82 | bool is_forward_request() const { return m_forward_request ; } ; 83 | bool is_leader() const { return m_node_info.node_id == m_node_info.leader_id ; } ; 84 | void set_leader(const VoteData& vote_data) ; 85 | //get leader connectioin 86 | ServerHandler* get_leader() ; 87 | 88 | int broadcast(framework::packet* p) { return m_server_manager.broadcast(m_node_info.node_type,p); } ; 89 | 90 | AsyncProcessorManager& async_manager() { return m_processor_manager ; } ; 91 | 92 | void stop_vote() ; 93 | 94 | //worker event 95 | void on_event(int64_t v) ; 96 | void on_queue_log(SyncQueueData& log_data) ; 97 | Worker& get_worker() { return m_worker ; } ; 98 | int send_event(SyncQueueData* data) ; 99 | 100 | protected: 101 | int load_cluster_config(const Value& root) ; 102 | int load_node_config(const Value& root) ; 103 | int load_reload_config(const Value& root) ; 104 | int load_virtual_queue(const Value& root) ; 105 | 106 | int on_init() ; 107 | 108 | int on_reload() ; 109 | 110 | void on_fini() ; 111 | 112 | void on_delay_stop() ; 113 | 114 | void on_timer() ; 115 | 116 | int start_vote() ; 117 | 118 | void check_leader(); 119 | 120 | /** 121 | * @brief timer to restart sync 122 | */ 123 | void on_sync_timeout(framework::timer_manager* manager) ; 124 | 125 | /** 126 | * @brief slave node try sync data from master node 127 | */ 128 | void try_sync_queue() ; 129 | 130 | const SyncQueueData& update_queue_log(SyncQueueData& sync_data); 131 | private: 132 | framework::base_timer m_sync_timer ; 133 | framework::day_roll_logger m_logger ; 134 | framework::tcp_acceptor m_server_acceptor ; 135 | framework::eventfd_handler m_event_handler ; 136 | EventQueue m_event_queue ; 137 | framework::log_thread m_log_thread ; 138 | Worker m_worker ; 139 | 140 | ServerManager m_server_manager ; 141 | std::set m_push_sync_set ; 142 | ServerInfoContainer m_cluster_info ; // node list in cluster 143 | 144 | QueueLogContainer m_queue_log ; 145 | AsyncProcessorManager m_processor_manager ; 146 | QueueConfig m_queue_config ; 147 | VoteData m_self_vote_info ; // self vote info 148 | framework::object_switcher m_leader_vote_info ; // leader vote info 149 | NodeData m_node_info ; // node info and status 150 | int m_sync_counter ; 151 | int m_sync_time ; 152 | bool m_forward_request ; 153 | 154 | }; 155 | 156 | inline QueueServer& get_app() { return framework::singleton() ; }; 157 | 158 | 159 | -------------------------------------------------------------------------------- /queue_server/server_ctl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/env bash 2 | 3 | ############### function ############ 4 | 5 | 6 | server_pid() 7 | { 8 | #ps -e -o pid,args |grep -v grep |grep "$1" | awk '{print $1}' 9 | pgrep -fx "$1" | awk '{printf("%d ",$1);}' 10 | } 11 | 12 | start_server() 13 | { 14 | echo "running [$1]" 15 | $1 16 | sleep 1 17 | 18 | } 19 | 20 | 21 | stop_server() 22 | { 23 | pid=$(server_pid "$1") 24 | if [ ${#pid} -gt 0 ] ;then 25 | echo "stopping [$pid $1]" 26 | kill -USR2 $pid 27 | sleep 1 28 | else 29 | echo "cannot find [$1]" 30 | fi 31 | } 32 | 33 | reload_server() 34 | { 35 | pid=$(server_pid "$1") 36 | if [ ${#pid} -gt 0 ] ;then 37 | echo "reloading [$pid $1]" 38 | kill -USR1 $pid 39 | sleep 1 40 | else 41 | echo "cannot find [$1]" 42 | fi 43 | } 44 | 45 | 46 | 47 | ############## main ################ 48 | 49 | if [ $# -lt 3 ] ; then 50 | echo "usage:$0 start|stop|reload queue_server {node_id}" 51 | exit 52 | fi 53 | 54 | command="$1" 55 | server="$2" 56 | node_id="$3" 57 | 58 | cd $(dirname $0) 59 | base_dir=$(pwd) 60 | echo "change dir to [$base_dir] " 61 | cd $base_dir 62 | 63 | server_cmd="" 64 | 65 | case "$server" in 66 | queue_server) 67 | server_cmd="./queue_server.bin -c queue_server_${node_id}.xml -w $base_dir -d" 68 | ;; 69 | *) 70 | echo "invalid server, quit" 71 | exit 1 72 | ;; 73 | 74 | esac 75 | 76 | 77 | case "$command" in 78 | start) 79 | start_server "$server_cmd" 80 | ;; 81 | stop) 82 | stop_server "$server_cmd" 83 | ;; 84 | reload) 85 | reload_server "$server_cmd" 86 | ;; 87 | *) 88 | echo "invalid command , quit" 89 | exit 1 90 | ;; 91 | esac 92 | -------------------------------------------------------------------------------- /queue_server/worker.h: -------------------------------------------------------------------------------- 1 | /* 2 | * worker.h 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "framework/thread.h" 13 | #include "framework/eventfd_handler.h" 14 | #include "framework/epoll_reactor.h" 15 | #include "framework/circular_queue.h" 16 | #include "framework/log_thread.h" 17 | #include "framework/timer_manager.h" 18 | #include "framework/object_pool.h" 19 | #include "framework/tcp_acceptor.h" 20 | #include "public/system.pb.h" 21 | #include "queue.h" 22 | #include "client_udp_handler.h" 23 | #include "client_tcp_handler.h" 24 | 25 | #include "rapidjson/document.h" 26 | #include "rapidjson/stringbuffer.h" 27 | 28 | using rapidjson::Document ; 29 | using rapidjson::Value ; 30 | using rapidjson::Type; 31 | using rapidjson::StringBuffer; 32 | 33 | using framework::eventfd_handler ; 34 | using framework::log_thread ; 35 | using framework::poll_reactor ; 36 | 37 | typedef std::vector QueueNameContainer ; 38 | typedef std::tr1::unordered_map VirtualQueueContainer ; 39 | 40 | typedef framework::object_pool ClientPool ; 41 | 42 | struct LocalEventData 43 | { 44 | int type; 45 | int timestamp ; 46 | void* data ; 47 | } ; 48 | 49 | struct SourceData 50 | { 51 | int is_tcp ; 52 | framework::sa_in_t addr ; 53 | framework::tcp_data_handler::connection_id id ; 54 | }; 55 | 56 | typedef framework::circular_queue EventQueue ; 57 | 58 | class Worker: public framework::simple_thread 59 | { 60 | public: 61 | Worker(framework::log_thread& logger); 62 | virtual ~Worker(); 63 | 64 | int init(VirtualQueueContainer& virtual_queue) ; 65 | 66 | //tcp client connection callback 67 | int on_client_connection(int fd,sa_in_t* addr); 68 | void on_client_closed(ClientTcpHandler* client_handler) ; 69 | void free_connection(ClientTcpHandler* client_handler); 70 | 71 | //notify event , called by main thread 72 | int notify_sync_request(const SyncQueueData& data) ; 73 | int notify_leader_change() ; 74 | int notify_queue_config(VirtualQueueContainer& virtual_queue) ; 75 | 76 | //notify callback 77 | void on_event(int64_t v) ; 78 | void on_sync_request(void* data) ; 79 | void on_leader_change(void* data) ; 80 | void on_queue_config(void* data) ; 81 | 82 | //process forward packet 83 | int process_forward_request(ClientTcpHandler* handler,const framework::packet_info* pi) ; 84 | int process_forward_response(ClientTcpHandler* handler,const framework::packet_info* pi) ; 85 | int forward_to_leader(const SourceData& source,const char* data,int size) ; 86 | 87 | Queue* get_queue(const string& queue_name); 88 | const QueueNameContainer* real_queue_name(const std::string& name); 89 | framework::log_thread& logger() { return m_logger ; } ; 90 | 91 | //timer api 92 | int add_timer_after(framework::base_timer* timer,int seconds) ; 93 | void del_timer(framework::base_timer* timer) ; 94 | void on_timeout(framework::timer_manager* manager) ; 95 | 96 | void list_queue(Document& queue_list,const char* pattern) ; 97 | 98 | 99 | protected: 100 | virtual int on_init() ; 101 | virtual void on_fini() ; 102 | virtual void run_once() ; 103 | 104 | /** 105 | * @brief process sync queue event 106 | */ 107 | void process_sync_queue(SyncQueueData& sync_data) ; 108 | 109 | /** 110 | * @brief send event to worker 111 | */ 112 | int send_event(int type,void* data) ; 113 | 114 | int init_leader_handler() ; 115 | private: 116 | framework::base_timer m_timer ; 117 | framework::log_thread& m_logger ; 118 | framework::epoll_reactor m_reactor ; 119 | framework::timer_manager m_timer_engine ; 120 | framework::eventfd_handler m_event_handler ; 121 | EventQueue m_event_queue ; 122 | VirtualQueueContainer m_virtual_queue ; 123 | QueueManager m_queue_manager ; 124 | ClientUdpHandler m_udp_handler ; 125 | ClientTcpHandler m_leader_handler ; 126 | framework::tcp_acceptor m_client_acceptor ; 127 | ClientPool m_client_pool ; 128 | 129 | }; 130 | 131 | typedef std::map JsonFieldInfo ; 132 | 133 | /* 134 | * @brief check field and value type of json object 135 | * @return true on success 136 | */ 137 | bool json_check_field(const Value&json,const JsonFieldInfo& field_list) ; 138 | 139 | /** 140 | * @brief parse request data 141 | * @return 0 on success 142 | */ 143 | int json_decode(const char* begin,const char* end,Document& request) ; 144 | 145 | /** 146 | * @brief serialize json object 147 | * @return true on success 148 | */ 149 | bool json_encode(const Value& json,StringBuffer& buffer) ; 150 | 151 | /** 152 | * @brief get value from json object 153 | * @param json json object 154 | * @param key 155 | * @param default_value 156 | * @return value 157 | */ 158 | int json_get_value(const Value& json,const char* key,int default_value); 159 | 160 | const char* json_get_value(const Value& json,const char* key,const char* default_value); 161 | 162 | -------------------------------------------------------------------------------- /queue_server/worker_util.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | */ 5 | 6 | #include "worker_util.h" 7 | #include "queue_server.h" 8 | 9 | Worker& get_worker() 10 | { 11 | return get_app().get_worker() ; 12 | 13 | } 14 | log_thread& get_logger() 15 | { 16 | return get_worker().logger() ; 17 | } 18 | 19 | VoteData& get_leader_vote_data(VoteData& data) 20 | { 21 | data.CopyFrom(get_app().leader_vote_data()) ; 22 | return data ; 23 | } 24 | 25 | VoteData& get_self_vote_data(VoteData& data) 26 | { 27 | data.CopyFrom(get_app().self_vote_data() ) ; 28 | return data ; 29 | } 30 | 31 | int max_queue_size() 32 | { 33 | return get_app().queue_size() ; 34 | } 35 | 36 | bool is_leader() 37 | { 38 | return get_app().is_leader() ; 39 | } 40 | 41 | bool is_forward_request() 42 | { 43 | return get_app().is_forward_request() ; 44 | } 45 | 46 | int notify_sync_event(SyncQueueData* data) 47 | { 48 | return get_app().send_event(data) ; 49 | } 50 | 51 | -------------------------------------------------------------------------------- /queue_server/worker_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: lxyfirst@163.com 3 | */ 4 | 5 | #pragma once 6 | 7 | #include "worker.h" 8 | 9 | Worker& get_worker() ; 10 | log_thread& get_logger() ; 11 | 12 | VoteData& get_leader_vote_data(VoteData& data); 13 | VoteData& get_self_vote_data(VoteData& data); 14 | 15 | int max_queue_size() ; 16 | 17 | bool is_leader() ; 18 | 19 | bool is_forward_request() ; 20 | 21 | int notify_sync_event(SyncQueueData* data) ; 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /rapidjson/error/en.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_ERROR_EN_H_ 16 | #define RAPIDJSON_ERROR_EN_H_ 17 | 18 | #include "error.h" 19 | 20 | #ifdef __clang__ 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(switch-enum) 23 | RAPIDJSON_DIAG_OFF(covered-switch-default) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Maps error code of parsing into error message. 29 | /*! 30 | \ingroup RAPIDJSON_ERRORS 31 | \param parseErrorCode Error code obtained in parsing. 32 | \return the error message. 33 | \note User can make a copy of this function for localization. 34 | Using switch-case is safer for future modification of error codes. 35 | */ 36 | inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { 37 | switch (parseErrorCode) { 38 | case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); 39 | 40 | case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); 41 | case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); 42 | 43 | case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); 44 | 45 | case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); 46 | case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); 47 | case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); 48 | 49 | case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); 50 | 51 | case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); 52 | case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); 53 | case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); 54 | case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); 55 | case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); 56 | 57 | case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); 58 | case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); 59 | case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); 60 | 61 | case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); 62 | case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); 63 | 64 | default: return RAPIDJSON_ERROR_STRING("Unknown error."); 65 | } 66 | } 67 | 68 | RAPIDJSON_NAMESPACE_END 69 | 70 | #ifdef __clang__ 71 | RAPIDJSON_DIAG_POP 72 | #endif 73 | 74 | #endif // RAPIDJSON_ERROR_EN_H_ 75 | -------------------------------------------------------------------------------- /rapidjson/filereadstream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FILEREADSTREAM_H_ 16 | #define RAPIDJSON_FILEREADSTREAM_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(padded) 24 | RAPIDJSON_DIAG_OFF(unreachable-code) 25 | RAPIDJSON_DIAG_OFF(missing-noreturn) 26 | #endif 27 | 28 | RAPIDJSON_NAMESPACE_BEGIN 29 | 30 | //! File byte stream for input using fread(). 31 | /*! 32 | \note implements Stream concept 33 | */ 34 | class FileReadStream { 35 | public: 36 | typedef char Ch; //!< Character type (byte). 37 | 38 | //! Constructor. 39 | /*! 40 | \param fp File pointer opened for read. 41 | \param buffer user-supplied buffer. 42 | \param bufferSize size of buffer in bytes. Must >=4 bytes. 43 | */ 44 | FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 45 | RAPIDJSON_ASSERT(fp_ != 0); 46 | RAPIDJSON_ASSERT(bufferSize >= 4); 47 | Read(); 48 | } 49 | 50 | Ch Peek() const { return *current_; } 51 | Ch Take() { Ch c = *current_; Read(); return c; } 52 | size_t Tell() const { return count_ + static_cast(current_ - buffer_); } 53 | 54 | // Not implemented 55 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 56 | void Flush() { RAPIDJSON_ASSERT(false); } 57 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 58 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 59 | 60 | // For encoding detection only. 61 | const Ch* Peek4() const { 62 | return (current_ + 4 <= bufferLast_) ? current_ : 0; 63 | } 64 | 65 | private: 66 | void Read() { 67 | if (current_ < bufferLast_) 68 | ++current_; 69 | else if (!eof_) { 70 | count_ += readCount_; 71 | readCount_ = fread(buffer_, 1, bufferSize_, fp_); 72 | bufferLast_ = buffer_ + readCount_ - 1; 73 | current_ = buffer_; 74 | 75 | if (readCount_ < bufferSize_) { 76 | buffer_[readCount_] = '\0'; 77 | ++bufferLast_; 78 | eof_ = true; 79 | } 80 | } 81 | } 82 | 83 | std::FILE* fp_; 84 | Ch *buffer_; 85 | size_t bufferSize_; 86 | Ch *bufferLast_; 87 | Ch *current_; 88 | size_t readCount_; 89 | size_t count_; //!< Number of characters read 90 | bool eof_; 91 | }; 92 | 93 | RAPIDJSON_NAMESPACE_END 94 | 95 | #ifdef __clang__ 96 | RAPIDJSON_DIAG_POP 97 | #endif 98 | 99 | #endif // RAPIDJSON_FILESTREAM_H_ 100 | -------------------------------------------------------------------------------- /rapidjson/filewritestream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FILEWRITESTREAM_H_ 16 | #define RAPIDJSON_FILEWRITESTREAM_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(unreachable-code) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Wrapper of C file stream for input using fread(). 29 | /*! 30 | \note implements Stream concept 31 | */ 32 | class FileWriteStream { 33 | public: 34 | typedef char Ch; //!< Character type. Only support char. 35 | 36 | FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { 37 | RAPIDJSON_ASSERT(fp_ != 0); 38 | } 39 | 40 | void Put(char c) { 41 | if (current_ >= bufferEnd_) 42 | Flush(); 43 | 44 | *current_++ = c; 45 | } 46 | 47 | void PutN(char c, size_t n) { 48 | size_t avail = static_cast(bufferEnd_ - current_); 49 | while (n > avail) { 50 | std::memset(current_, c, avail); 51 | current_ += avail; 52 | Flush(); 53 | n -= avail; 54 | avail = static_cast(bufferEnd_ - current_); 55 | } 56 | 57 | if (n > 0) { 58 | std::memset(current_, c, n); 59 | current_ += n; 60 | } 61 | } 62 | 63 | void Flush() { 64 | if (current_ != buffer_) { 65 | size_t result = fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); 66 | if (result < static_cast(current_ - buffer_)) { 67 | // failure deliberately ignored at this time 68 | // added to avoid warn_unused_result build errors 69 | } 70 | current_ = buffer_; 71 | } 72 | } 73 | 74 | // Not implemented 75 | char Peek() const { RAPIDJSON_ASSERT(false); return 0; } 76 | char Take() { RAPIDJSON_ASSERT(false); return 0; } 77 | size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } 78 | char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 79 | size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } 80 | 81 | private: 82 | // Prohibit copy constructor & assignment operator. 83 | FileWriteStream(const FileWriteStream&); 84 | FileWriteStream& operator=(const FileWriteStream&); 85 | 86 | std::FILE* fp_; 87 | char *buffer_; 88 | char *bufferEnd_; 89 | char *current_; 90 | }; 91 | 92 | //! Implement specialized version of PutN() with memset() for better performance. 93 | template<> 94 | inline void PutN(FileWriteStream& stream, char c, size_t n) { 95 | stream.PutN(c, n); 96 | } 97 | 98 | RAPIDJSON_NAMESPACE_END 99 | 100 | #ifdef __clang__ 101 | RAPIDJSON_DIAG_POP 102 | #endif 103 | 104 | #endif // RAPIDJSON_FILESTREAM_H_ 105 | -------------------------------------------------------------------------------- /rapidjson/fwd.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FWD_H_ 16 | #define RAPIDJSON_FWD_H_ 17 | 18 | #include "rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | 22 | // encodings.h 23 | 24 | template struct UTF8; 25 | template struct UTF16; 26 | template struct UTF16BE; 27 | template struct UTF16LE; 28 | template struct UTF32; 29 | template struct UTF32BE; 30 | template struct UTF32LE; 31 | template struct ASCII; 32 | template struct AutoUTF; 33 | 34 | template 35 | struct Transcoder; 36 | 37 | // allocators.h 38 | 39 | class CrtAllocator; 40 | 41 | template 42 | class MemoryPoolAllocator; 43 | 44 | // stream.h 45 | 46 | template 47 | struct GenericStringStream; 48 | 49 | typedef GenericStringStream > StringStream; 50 | 51 | template 52 | struct GenericInsituStringStream; 53 | 54 | typedef GenericInsituStringStream > InsituStringStream; 55 | 56 | // stringbuffer.h 57 | 58 | template 59 | class GenericStringBuffer; 60 | 61 | typedef GenericStringBuffer, CrtAllocator> StringBuffer; 62 | 63 | // filereadstream.h 64 | 65 | class FileReadStream; 66 | 67 | // filewritestream.h 68 | 69 | class FileWriteStream; 70 | 71 | // memorybuffer.h 72 | 73 | template 74 | struct GenericMemoryBuffer; 75 | 76 | typedef GenericMemoryBuffer MemoryBuffer; 77 | 78 | // memorystream.h 79 | 80 | struct MemoryStream; 81 | 82 | // reader.h 83 | 84 | template 85 | struct BaseReaderHandler; 86 | 87 | template 88 | class GenericReader; 89 | 90 | typedef GenericReader, UTF8, CrtAllocator> Reader; 91 | 92 | // writer.h 93 | 94 | template 95 | class Writer; 96 | 97 | // prettywriter.h 98 | 99 | template 100 | class PrettyWriter; 101 | 102 | // document.h 103 | 104 | template 105 | struct GenericMember; 106 | 107 | template 108 | class GenericMemberIterator; 109 | 110 | template 111 | struct GenericStringRef; 112 | 113 | template 114 | class GenericValue; 115 | 116 | typedef GenericValue, MemoryPoolAllocator > Value; 117 | 118 | template 119 | class GenericDocument; 120 | 121 | typedef GenericDocument, MemoryPoolAllocator, CrtAllocator> Document; 122 | 123 | // pointer.h 124 | 125 | template 126 | class GenericPointer; 127 | 128 | typedef GenericPointer Pointer; 129 | 130 | // schema.h 131 | 132 | template 133 | class IGenericRemoteSchemaDocumentProvider; 134 | 135 | template 136 | class GenericSchemaDocument; 137 | 138 | typedef GenericSchemaDocument SchemaDocument; 139 | typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; 140 | 141 | template < 142 | typename SchemaDocumentType, 143 | typename OutputHandler, 144 | typename StateAllocator> 145 | class GenericSchemaValidator; 146 | 147 | typedef GenericSchemaValidator, void>, CrtAllocator> SchemaValidator; 148 | 149 | RAPIDJSON_NAMESPACE_END 150 | 151 | #endif // RAPIDJSON_RAPIDJSONFWD_H_ 152 | -------------------------------------------------------------------------------- /rapidjson/internal/ieee754.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_IEEE754_ 16 | #define RAPIDJSON_IEEE754_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | namespace internal { 22 | 23 | class Double { 24 | public: 25 | Double() {} 26 | Double(double d) : d_(d) {} 27 | Double(uint64_t u) : u_(u) {} 28 | 29 | double Value() const { return d_; } 30 | uint64_t Uint64Value() const { return u_; } 31 | 32 | double NextPositiveDouble() const { 33 | RAPIDJSON_ASSERT(!Sign()); 34 | return Double(u_ + 1).Value(); 35 | } 36 | 37 | bool Sign() const { return (u_ & kSignMask) != 0; } 38 | uint64_t Significand() const { return u_ & kSignificandMask; } 39 | int Exponent() const { return static_cast(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); } 40 | 41 | bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } 42 | bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } 43 | bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; } 44 | bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } 45 | bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } 46 | 47 | uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } 48 | int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } 49 | uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } 50 | 51 | static int EffectiveSignificandSize(int order) { 52 | if (order >= -1021) 53 | return 53; 54 | else if (order <= -1074) 55 | return 0; 56 | else 57 | return order + 1074; 58 | } 59 | 60 | private: 61 | static const int kSignificandSize = 52; 62 | static const int kExponentBias = 0x3FF; 63 | static const int kDenormalExponent = 1 - kExponentBias; 64 | static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); 65 | static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); 66 | static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); 67 | static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); 68 | 69 | union { 70 | double d_; 71 | uint64_t u_; 72 | }; 73 | }; 74 | 75 | } // namespace internal 76 | RAPIDJSON_NAMESPACE_END 77 | 78 | #endif // RAPIDJSON_IEEE754_ 79 | -------------------------------------------------------------------------------- /rapidjson/internal/pow10.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_POW10_ 16 | #define RAPIDJSON_POW10_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | namespace internal { 22 | 23 | //! Computes integer powers of 10 in double (10.0^n). 24 | /*! This function uses lookup table for fast and accurate results. 25 | \param n non-negative exponent. Must <= 308. 26 | \return 10.0^n 27 | */ 28 | inline double Pow10(int n) { 29 | static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes 30 | 1e+0, 31 | 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 32 | 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, 33 | 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, 34 | 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, 35 | 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, 36 | 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, 37 | 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, 38 | 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, 39 | 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, 40 | 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, 41 | 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, 42 | 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, 43 | 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, 44 | 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, 45 | 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, 46 | 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 47 | }; 48 | RAPIDJSON_ASSERT(n >= 0 && n <= 308); 49 | return e[n]; 50 | } 51 | 52 | } // namespace internal 53 | RAPIDJSON_NAMESPACE_END 54 | 55 | #endif // RAPIDJSON_POW10_ 56 | -------------------------------------------------------------------------------- /rapidjson/internal/strfunc.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ 16 | #define RAPIDJSON_INTERNAL_STRFUNC_H_ 17 | 18 | #include "../stream.h" 19 | #include 20 | 21 | RAPIDJSON_NAMESPACE_BEGIN 22 | namespace internal { 23 | 24 | //! Custom strlen() which works on different character types. 25 | /*! \tparam Ch Character type (e.g. char, wchar_t, short) 26 | \param s Null-terminated input string. 27 | \return Number of characters in the string. 28 | \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. 29 | */ 30 | template 31 | inline SizeType StrLen(const Ch* s) { 32 | RAPIDJSON_ASSERT(s != 0); 33 | const Ch* p = s; 34 | while (*p) ++p; 35 | return SizeType(p - s); 36 | } 37 | 38 | template <> 39 | inline SizeType StrLen(const char* s) { 40 | return SizeType(std::strlen(s)); 41 | } 42 | 43 | template <> 44 | inline SizeType StrLen(const wchar_t* s) { 45 | return SizeType(std::wcslen(s)); 46 | } 47 | 48 | //! Returns number of code points in a encoded string. 49 | template 50 | bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { 51 | RAPIDJSON_ASSERT(s != 0); 52 | RAPIDJSON_ASSERT(outCount != 0); 53 | GenericStringStream is(s); 54 | const typename Encoding::Ch* end = s + length; 55 | SizeType count = 0; 56 | while (is.src_ < end) { 57 | unsigned codepoint; 58 | if (!Encoding::Decode(is, &codepoint)) 59 | return false; 60 | count++; 61 | } 62 | *outCount = count; 63 | return true; 64 | } 65 | 66 | } // namespace internal 67 | RAPIDJSON_NAMESPACE_END 68 | 69 | #endif // RAPIDJSON_INTERNAL_STRFUNC_H_ 70 | -------------------------------------------------------------------------------- /rapidjson/internal/swap.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_SWAP_H_ 16 | #define RAPIDJSON_INTERNAL_SWAP_H_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | #if defined(__clang__) 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(c++98-compat) 23 | #endif 24 | 25 | RAPIDJSON_NAMESPACE_BEGIN 26 | namespace internal { 27 | 28 | //! Custom swap() to avoid dependency on C++ header 29 | /*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. 30 | \note This has the same semantics as std::swap(). 31 | */ 32 | template 33 | inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { 34 | T tmp = a; 35 | a = b; 36 | b = tmp; 37 | } 38 | 39 | } // namespace internal 40 | RAPIDJSON_NAMESPACE_END 41 | 42 | #if defined(__clang__) 43 | RAPIDJSON_DIAG_POP 44 | #endif 45 | 46 | #endif // RAPIDJSON_INTERNAL_SWAP_H_ 47 | -------------------------------------------------------------------------------- /rapidjson/istreamwrapper.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_ISTREAMWRAPPER_H_ 16 | #define RAPIDJSON_ISTREAMWRAPPER_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(padded) 24 | #endif 25 | 26 | #ifdef _MSC_VER 27 | RAPIDJSON_DIAG_PUSH 28 | RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized 29 | #endif 30 | 31 | RAPIDJSON_NAMESPACE_BEGIN 32 | 33 | //! Wrapper of \c std::basic_istream into RapidJSON's Stream concept. 34 | /*! 35 | The classes can be wrapped including but not limited to: 36 | 37 | - \c std::istringstream 38 | - \c std::stringstream 39 | - \c std::wistringstream 40 | - \c std::wstringstream 41 | - \c std::ifstream 42 | - \c std::fstream 43 | - \c std::wifstream 44 | - \c std::wfstream 45 | 46 | \tparam StreamType Class derived from \c std::basic_istream. 47 | */ 48 | 49 | template 50 | class BasicIStreamWrapper { 51 | public: 52 | typedef typename StreamType::char_type Ch; 53 | BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {} 54 | 55 | Ch Peek() const { 56 | typename StreamType::int_type c = stream_.peek(); 57 | return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast(c) : static_cast('\0'); 58 | } 59 | 60 | Ch Take() { 61 | typename StreamType::int_type c = stream_.get(); 62 | if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) { 63 | count_++; 64 | return static_cast(c); 65 | } 66 | else 67 | return '\0'; 68 | } 69 | 70 | // tellg() may return -1 when failed. So we count by ourself. 71 | size_t Tell() const { return count_; } 72 | 73 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 74 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 75 | void Flush() { RAPIDJSON_ASSERT(false); } 76 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 77 | 78 | // For encoding detection only. 79 | const Ch* Peek4() const { 80 | RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream. 81 | int i; 82 | bool hasError = false; 83 | for (i = 0; i < 4; ++i) { 84 | typename StreamType::int_type c = stream_.get(); 85 | if (c == StreamType::traits_type::eof()) { 86 | hasError = true; 87 | stream_.clear(); 88 | break; 89 | } 90 | peekBuffer_[i] = static_cast(c); 91 | } 92 | for (--i; i >= 0; --i) 93 | stream_.putback(peekBuffer_[i]); 94 | return !hasError ? peekBuffer_ : 0; 95 | } 96 | 97 | private: 98 | BasicIStreamWrapper(const BasicIStreamWrapper&); 99 | BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); 100 | 101 | StreamType& stream_; 102 | size_t count_; //!< Number of characters read. Note: 103 | mutable Ch peekBuffer_[4]; 104 | }; 105 | 106 | typedef BasicIStreamWrapper IStreamWrapper; 107 | typedef BasicIStreamWrapper WIStreamWrapper; 108 | 109 | #if defined(__clang__) || defined(_MSC_VER) 110 | RAPIDJSON_DIAG_POP 111 | #endif 112 | 113 | RAPIDJSON_NAMESPACE_END 114 | 115 | #endif // RAPIDJSON_ISTREAMWRAPPER_H_ 116 | -------------------------------------------------------------------------------- /rapidjson/memorybuffer.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_MEMORYBUFFER_H_ 16 | #define RAPIDJSON_MEMORYBUFFER_H_ 17 | 18 | #include "stream.h" 19 | #include "internal/stack.h" 20 | 21 | RAPIDJSON_NAMESPACE_BEGIN 22 | 23 | //! Represents an in-memory output byte stream. 24 | /*! 25 | This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream. 26 | 27 | It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. 28 | 29 | Differences between MemoryBuffer and StringBuffer: 30 | 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. 31 | 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. 32 | 33 | \tparam Allocator type for allocating memory buffer. 34 | \note implements Stream concept 35 | */ 36 | template 37 | struct GenericMemoryBuffer { 38 | typedef char Ch; // byte 39 | 40 | GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} 41 | 42 | void Put(Ch c) { *stack_.template Push() = c; } 43 | void Flush() {} 44 | 45 | void Clear() { stack_.Clear(); } 46 | void ShrinkToFit() { stack_.ShrinkToFit(); } 47 | Ch* Push(size_t count) { return stack_.template Push(count); } 48 | void Pop(size_t count) { stack_.template Pop(count); } 49 | 50 | const Ch* GetBuffer() const { 51 | return stack_.template Bottom(); 52 | } 53 | 54 | size_t GetSize() const { return stack_.GetSize(); } 55 | 56 | static const size_t kDefaultCapacity = 256; 57 | mutable internal::Stack stack_; 58 | }; 59 | 60 | typedef GenericMemoryBuffer<> MemoryBuffer; 61 | 62 | //! Implement specialized version of PutN() with memset() for better performance. 63 | template<> 64 | inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { 65 | std::memset(memoryBuffer.stack_.Push(n), c, n * sizeof(c)); 66 | } 67 | 68 | RAPIDJSON_NAMESPACE_END 69 | 70 | #endif // RAPIDJSON_MEMORYBUFFER_H_ 71 | -------------------------------------------------------------------------------- /rapidjson/memorystream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_MEMORYSTREAM_H_ 16 | #define RAPIDJSON_MEMORYSTREAM_H_ 17 | 18 | #include "stream.h" 19 | 20 | #ifdef __clang__ 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(unreachable-code) 23 | RAPIDJSON_DIAG_OFF(missing-noreturn) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Represents an in-memory input byte stream. 29 | /*! 30 | This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream. 31 | 32 | It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file. 33 | 34 | Differences between MemoryStream and StringStream: 35 | 1. StringStream has encoding but MemoryStream is a byte stream. 36 | 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source. 37 | 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). 38 | \note implements Stream concept 39 | */ 40 | struct MemoryStream { 41 | typedef char Ch; // byte 42 | 43 | MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} 44 | 45 | Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; } 46 | Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; } 47 | size_t Tell() const { return static_cast(src_ - begin_); } 48 | 49 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 50 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 51 | void Flush() { RAPIDJSON_ASSERT(false); } 52 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 53 | 54 | // For encoding detection only. 55 | const Ch* Peek4() const { 56 | return Tell() + 4 <= size_ ? src_ : 0; 57 | } 58 | 59 | const Ch* src_; //!< Current read position. 60 | const Ch* begin_; //!< Original head of the string. 61 | const Ch* end_; //!< End of stream. 62 | size_t size_; //!< Size of the stream. 63 | }; 64 | 65 | RAPIDJSON_NAMESPACE_END 66 | 67 | #ifdef __clang__ 68 | RAPIDJSON_DIAG_POP 69 | #endif 70 | 71 | #endif // RAPIDJSON_MEMORYBUFFER_H_ 72 | -------------------------------------------------------------------------------- /rapidjson/ostreamwrapper.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_OSTREAMWRAPPER_H_ 16 | #define RAPIDJSON_OSTREAMWRAPPER_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(padded) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept. 29 | /*! 30 | The classes can be wrapped including but not limited to: 31 | 32 | - \c std::ostringstream 33 | - \c std::stringstream 34 | - \c std::wpstringstream 35 | - \c std::wstringstream 36 | - \c std::ifstream 37 | - \c std::fstream 38 | - \c std::wofstream 39 | - \c std::wfstream 40 | 41 | \tparam StreamType Class derived from \c std::basic_ostream. 42 | */ 43 | 44 | template 45 | class BasicOStreamWrapper { 46 | public: 47 | typedef typename StreamType::char_type Ch; 48 | BasicOStreamWrapper(StreamType& stream) : stream_(stream) {} 49 | 50 | void Put(Ch c) { 51 | stream_.put(c); 52 | } 53 | 54 | void Flush() { 55 | stream_.flush(); 56 | } 57 | 58 | // Not implemented 59 | char Peek() const { RAPIDJSON_ASSERT(false); return 0; } 60 | char Take() { RAPIDJSON_ASSERT(false); return 0; } 61 | size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } 62 | char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 63 | size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } 64 | 65 | private: 66 | BasicOStreamWrapper(const BasicOStreamWrapper&); 67 | BasicOStreamWrapper& operator=(const BasicOStreamWrapper&); 68 | 69 | StreamType& stream_; 70 | }; 71 | 72 | typedef BasicOStreamWrapper OStreamWrapper; 73 | typedef BasicOStreamWrapper WOStreamWrapper; 74 | 75 | #ifdef __clang__ 76 | RAPIDJSON_DIAG_POP 77 | #endif 78 | 79 | RAPIDJSON_NAMESPACE_END 80 | 81 | #endif // RAPIDJSON_OSTREAMWRAPPER_H_ 82 | -------------------------------------------------------------------------------- /rapidjson/stringbuffer.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_STRINGBUFFER_H_ 16 | #define RAPIDJSON_STRINGBUFFER_H_ 17 | 18 | #include "stream.h" 19 | #include "internal/stack.h" 20 | 21 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 22 | #include // std::move 23 | #endif 24 | 25 | #include "internal/stack.h" 26 | 27 | #if defined(__clang__) 28 | RAPIDJSON_DIAG_PUSH 29 | RAPIDJSON_DIAG_OFF(c++98-compat) 30 | #endif 31 | 32 | RAPIDJSON_NAMESPACE_BEGIN 33 | 34 | //! Represents an in-memory output stream. 35 | /*! 36 | \tparam Encoding Encoding of the stream. 37 | \tparam Allocator type for allocating memory buffer. 38 | \note implements Stream concept 39 | */ 40 | template 41 | class GenericStringBuffer { 42 | public: 43 | typedef typename Encoding::Ch Ch; 44 | 45 | GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} 46 | 47 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 48 | GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {} 49 | GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { 50 | if (&rhs != this) 51 | stack_ = std::move(rhs.stack_); 52 | return *this; 53 | } 54 | #endif 55 | 56 | void Put(Ch c) { *stack_.template Push() = c; } 57 | void PutUnsafe(Ch c) { *stack_.template PushUnsafe() = c; } 58 | void Flush() {} 59 | 60 | void Clear() { stack_.Clear(); } 61 | void ShrinkToFit() { 62 | // Push and pop a null terminator. This is safe. 63 | *stack_.template Push() = '\0'; 64 | stack_.ShrinkToFit(); 65 | stack_.template Pop(1); 66 | } 67 | 68 | void Reserve(size_t count) { stack_.template Reserve(count); } 69 | Ch* Push(size_t count) { return stack_.template Push(count); } 70 | Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe(count); } 71 | void Pop(size_t count) { stack_.template Pop(count); } 72 | 73 | const Ch* GetString() const { 74 | // Push and pop a null terminator. This is safe. 75 | *stack_.template Push() = '\0'; 76 | stack_.template Pop(1); 77 | 78 | return stack_.template Bottom(); 79 | } 80 | 81 | //! Get the size of string in bytes in the string buffer. 82 | size_t GetSize() const { return stack_.GetSize(); } 83 | 84 | //! Get the length of string in Ch in the string buffer. 85 | size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); } 86 | 87 | static const size_t kDefaultCapacity = 256; 88 | mutable internal::Stack stack_; 89 | 90 | private: 91 | // Prohibit copy constructor & assignment operator. 92 | GenericStringBuffer(const GenericStringBuffer&); 93 | GenericStringBuffer& operator=(const GenericStringBuffer&); 94 | }; 95 | 96 | //! String buffer with UTF8 encoding 97 | typedef GenericStringBuffer > StringBuffer; 98 | 99 | template 100 | inline void PutReserve(GenericStringBuffer& stream, size_t count) { 101 | stream.Reserve(count); 102 | } 103 | 104 | template 105 | inline void PutUnsafe(GenericStringBuffer& stream, typename Encoding::Ch c) { 106 | stream.PutUnsafe(c); 107 | } 108 | 109 | //! Implement specialized version of PutN() with memset() for better performance. 110 | template<> 111 | inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { 112 | std::memset(stream.stack_.Push(n), c, n * sizeof(c)); 113 | } 114 | 115 | RAPIDJSON_NAMESPACE_END 116 | 117 | #if defined(__clang__) 118 | RAPIDJSON_DIAG_POP 119 | #endif 120 | 121 | #endif // RAPIDJSON_STRINGBUFFER_H_ 122 | -------------------------------------------------------------------------------- /test/bench_queue.py: -------------------------------------------------------------------------------- 1 | #!/bin/env python3 2 | 3 | import argparse 4 | import sys 5 | import asyncio 6 | import json 7 | import time 8 | import signal 9 | 10 | class GlobalConfig: 11 | request = 0 12 | started = 0 13 | stopped = 0 14 | connections = [] 15 | 16 | @classmethod 17 | def inc_started(cls) : 18 | cls.started +=1 19 | 20 | @classmethod 21 | def inc_stopped(cls) : 22 | cls.stopped +=1 23 | 24 | @classmethod 25 | def stop_all(cls): 26 | print('stop all') 27 | for connection in cls.connections : connection.abort() 28 | 29 | @classmethod 30 | def try_stop(cls): 31 | if cls.started == cls.stopped : 32 | loop = asyncio.get_event_loop() 33 | loop.stop() 34 | 35 | 36 | 37 | class ClientProtocol(asyncio.DatagramProtocol): 38 | def __init__(self): 39 | self.max_count = 0 40 | self.request = 0 41 | self.success = 0 42 | self.total_time = 0 43 | self.min_time = 9999999 44 | self.max_time = 0.0 45 | 46 | def send_request(self,data): 47 | self.transport.sendto(json.dumps(data).encode()) 48 | self.request +=1 49 | self.begin_request = time.time() 50 | #print('send "{}"'.format(data)) 51 | 52 | def send_produce(self): 53 | delay = int(time.time()) 54 | ttl = delay + 300 55 | retry = 30 56 | queue_data = 'this is queue data from request : %d' % self.request 57 | data = {'action':1,'queue':'test1','delay':delay,'ttl':ttl,'retry':retry,'data':queue_data} 58 | self.send_request(data) 59 | 60 | def send_consume(self): 61 | data = {'action':2,'queue':'test1'} 62 | self.send_request(data) 63 | 64 | def send_confirm(self,queue,msg_id): 65 | data = { 'action':3,'msg_id':msg_id,'queue':queue } 66 | self.send_request(data) 67 | 68 | def send_list_queue(self): 69 | data = { 'action':7} 70 | self.send_request(data) 71 | 72 | 73 | 74 | def on_start(self): 75 | if self.request >= GlobalConfig.request : 76 | self.transport.close() 77 | else : 78 | #self.send_produce() 79 | self.send_list_queue() 80 | 81 | def on_result(self,response): 82 | if 'msg_id' in response and response['action'] in [1,2] : 83 | queue = response['queue'] 84 | msg_id = int(response['msg_id']) 85 | self.send_confirm(queue,msg_id) 86 | else : 87 | self.on_start() 88 | 89 | 90 | def connection_made(self, transport): 91 | GlobalConfig.started +=1 92 | self.transport = transport 93 | self.begin_time = time.time() 94 | self.on_start() 95 | 96 | def datagram_received(self, data, addr): 97 | #print('received "{}"'.format(data)) 98 | try: 99 | request_time = time.time() - self.begin_request 100 | if request_time > 0.0 : 101 | self.total_time += request_time 102 | if request_time > self.max_time : self.max_time = request_time 103 | if request_time < self.min_time : self.min_time = request_time 104 | 105 | response = json.loads(data.decode()) 106 | if response['code'] == 0 : self.success +=1 107 | self.on_result(response) 108 | except Exception as ex: 109 | print(ex) 110 | 111 | 112 | def error_received(self, exc): 113 | print('Error received:', exc) 114 | 115 | def connection_lost(self, exc): 116 | consume_time = time.time() - self.begin_time 117 | avg_time = self.total_time/self.request if self.request >0 else 0.0 118 | print('counter:%d success:%d consume:%f avg:%f min:%f max:%f' % 119 | (self.request,self.success,consume_time,avg_time,self.min_time,self.max_time) ) 120 | GlobalConfig.stopped +=1 121 | GlobalConfig.try_stop() 122 | 123 | 124 | 125 | 126 | def parse_args(): 127 | parser = argparse.ArgumentParser(description="bench tool") 128 | parser.add_argument( '--host', dest='host', default='127.0.0.1', help='Host name') 129 | parser.add_argument( '--port', dest='port', default=1111, type=int, help='Port number') 130 | parser.add_argument( '-c', dest='concurrent', default=8, type=int, help='concurrent count') 131 | parser.add_argument( '-n', dest='request', default=1000, type=int, help='request count') 132 | return parser.parse_args() 133 | 134 | if __name__ == '__main__': 135 | args = parse_args() 136 | if ':' in args.host: 137 | args.host, port = args.host.split(':', 1) 138 | args.port = int(port) 139 | 140 | GlobalConfig.request = args.request 141 | 142 | loop = asyncio.get_event_loop() 143 | if signal is not None: 144 | loop.add_signal_handler(signal.SIGINT, GlobalConfig.stop_all ) 145 | 146 | for x in range(0,args.concurrent): 147 | t = asyncio.Task(loop.create_datagram_endpoint(ClientProtocol,remote_addr=(args.host, args.port))) 148 | loop.run_until_complete(t) 149 | transport,protocol = t.result() 150 | protocol.max_count = args.request 151 | GlobalConfig.connections.append(transport) 152 | 153 | try: 154 | loop.run_forever() 155 | 156 | finally: 157 | loop.close() 158 | 159 | --------------------------------------------------------------------------------