ChipMaster's trial hacks on C++CMS starting with v1.2.1. Not sure I'll follow on with the v2 since it looks to be breaking and mostly frivolous.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

304 lines
6.3 KiB

  1. #include "config.h"
  2. #ifdef __CYGWIN__
  3. // Cygwin ASIO works only with win32 sockets
  4. #define _WIN32_WINNT 1
  5. #define __USE_W32_SOCKETS 1
  6. #endif
  7. #ifdef USE_BOOST_ASIO
  8. #include <boost/asio.hpp>
  9. namespace aio = boost::asio;
  10. using boost::system::error_code;
  11. using boost::system::system_error;
  12. #else
  13. #include <asio.hpp>
  14. namespace aio = asio;
  15. using asio::error_code;
  16. using asio::system_error;
  17. #endif
  18. #include "tcp_cache.h"
  19. #include "tcp_cache_protocol.h"
  20. #include "archive.h"
  21. using aio::ip::tcp;
  22. namespace cppcms {
  23. class messenger : boost::noncopyable {
  24. aio::io_service srv_;
  25. tcp::socket socket_;
  26. string ip_;
  27. int port_;
  28. public:
  29. void connect(string ip,int port) {
  30. ip_=ip;
  31. port_=port;
  32. error_code e;
  33. socket_.connect(tcp::endpoint(aio::ip::address::from_string(ip),port),e);
  34. if(e) throw cppcms_error("connect:"+e.message());
  35. tcp::no_delay nd(true);
  36. socket_.set_option(nd);
  37. }
  38. messenger(string ip,int port) :
  39. socket_(srv_)
  40. {
  41. connect(ip,port);
  42. }
  43. messenger() : socket_(srv_) { };
  44. void transmit(tcp_operation_header &h,string &data)
  45. {
  46. bool done=false;
  47. int times=0;
  48. do {
  49. try {
  50. aio::write(socket_,aio::buffer(&h,sizeof(h)));
  51. if(h.size>0) {
  52. aio::write(socket_,aio::buffer(data,h.size));
  53. }
  54. aio::read(socket_,aio::buffer(&h,sizeof(h)));
  55. if(h.size>0) {
  56. vector<char> d(h.size);
  57. aio::read(socket_,aio::buffer(d,h.size));
  58. data.assign(d.begin(),d.begin()+h.size);
  59. }
  60. done=true;
  61. }
  62. catch(system_error const &e) {
  63. if(times) {
  64. throw cppcms_error(string("tcp_cache:")+e.what());
  65. }
  66. socket_.close();
  67. error_code er;
  68. socket_.connect(
  69. tcp::endpoint(
  70. aio::ip::address::from_string(ip_),port_),er);
  71. if(er) throw cppcms_error("reconnect:"+er.message());
  72. times++;
  73. }
  74. }while(!done);
  75. }
  76. };
  77. tcp_cache::tcp_cache(vector<string> const& ip,vector<long> const &port)
  78. {
  79. if(ip.size()<1 || port.size()!=ip.size()) {
  80. throw cppcms_error("Incorrect parameters for tcp cache");
  81. }
  82. conns=ip.size();
  83. tcp=new messenger[conns];
  84. try {
  85. for(int i=0;i<conns;i++) {
  86. tcp[i].connect(ip[i],port[i]);
  87. }
  88. }
  89. catch(...) {
  90. delete [] tcp;
  91. tcp=NULL;
  92. throw;
  93. }
  94. }
  95. tcp_cache::~tcp_cache()
  96. {
  97. delete [] tcp;
  98. }
  99. void tcp_cache::broadcast(tcp_operation_header &h,string &data)
  100. {
  101. int i;
  102. for(i=0;i<conns;i++) {
  103. tcp_operation_header ht=h;
  104. string dt=data;
  105. tcp[i].transmit(ht,data);
  106. }
  107. }
  108. void tcp_cache::rise(string const &trigger)
  109. {
  110. tcp_operation_header h={0};
  111. h.opcode=opcodes::rise;
  112. h.size=trigger.size();
  113. string data=trigger;
  114. h.operations.rise.trigger_len=trigger.size();
  115. broadcast(h,data);
  116. }
  117. void tcp_cache::clear()
  118. {
  119. tcp_operation_header h={0};
  120. h.opcode=opcodes::clear;
  121. h.size=0;
  122. string empty;
  123. broadcast(h,empty);
  124. }
  125. bool tcp_cache::fetch_page(string const &key,string &output,bool gzip)
  126. {
  127. string data=key;
  128. tcp_operation_header h={0};
  129. h.opcode=opcodes::fetch_page;
  130. h.size=data.size();
  131. h.operations.fetch_page.gzip=gzip;
  132. h.operations.fetch_page.strlen=data.size();
  133. get(key).transmit(h,data);
  134. if(h.opcode==opcodes::page_data) {
  135. output=data;
  136. return true;
  137. }
  138. return false;
  139. }
  140. bool tcp_cache::fetch(string const &key,archive &a,set<string> &tags)
  141. {
  142. string data=key;
  143. tcp_operation_header h={0};
  144. h.opcode=opcodes::fetch;
  145. h.size=data.size();
  146. h.operations.fetch.key_len=data.size();
  147. get(key).transmit(h,data);
  148. if(h.opcode!=opcodes::data)
  149. return false;
  150. char const *ptr=data.c_str();
  151. a.set(ptr,h.operations.data.data_len);
  152. ptr+=h.operations.data.data_len;
  153. int len=h.operations.data.triggers_len;
  154. while(len>0) {
  155. string tag;
  156. unsigned tmp_len=strlen(ptr);
  157. tag.assign(ptr,tmp_len);
  158. ptr+=tmp_len+1;
  159. len-=tmp_len+1;
  160. tags.insert(tag);
  161. }
  162. return true;
  163. }
  164. void tcp_cache::stats(unsigned &keys,unsigned &triggers)
  165. {
  166. keys=0; triggers=0;
  167. for(int i=0;i<conns;i++) {
  168. tcp_operation_header h={0};
  169. string data;
  170. h.opcode=opcodes::stats;
  171. tcp[i].transmit(h,data);
  172. if(h.opcode==opcodes::out_stats) {
  173. keys+=h.operations.out_stats.keys;
  174. triggers+=h.operations.out_stats.triggers;
  175. }
  176. }
  177. }
  178. void tcp_cache::store(string const &key,set<string> const &triggers,time_t timeout,archive const &a)
  179. {
  180. tcp_operation_header h={0};
  181. string data;
  182. h.opcode=opcodes::store;
  183. data.append(key);
  184. h.operations.store.key_len=key.size();
  185. data.append(a.get());
  186. h.operations.store.data_len=a.get().size();
  187. time_t now;
  188. time(&now);
  189. h.operations.store.timeout=timeout-now > 0 ? timeout-now : 0;
  190. unsigned tlen=0;
  191. for(set<string>::const_iterator p=triggers.begin(),e=triggers.end();p!=e;++p) {
  192. tlen+=p->size()+1;
  193. data.append(p->c_str(),p->size()+1);
  194. }
  195. h.operations.store.triggers_len=tlen;
  196. h.size=data.size();
  197. get(key).transmit(h,data);
  198. }
  199. messenger &tcp_cache::get(string const &key)
  200. {
  201. if(conns==1) return tcp[0];
  202. unsigned val=0,i;
  203. for(i=0;i<key.size();i++) {
  204. val+=251*key[i]+103 % 307;
  205. }
  206. return tcp[val % conns];
  207. }
  208. }
  209. #ifdef TCP_CACHE_UNIT_TEST
  210. #include <assert.h>
  211. #include <iostream>
  212. #include <cstdlib>
  213. int main(int argc,char **argv)
  214. {
  215. using namespace cppcms;
  216. using namespace std;
  217. if(argc!=3) {
  218. cerr<<"Usage IP port"<<endl;
  219. return 1;
  220. }
  221. try {
  222. archive a;
  223. set<string> s;
  224. tcp_cache tcp(argv[1],atoi(argv[2]));
  225. assert(tcp.fetch("something",a,s)==false);
  226. time_t t;
  227. time(&t);
  228. t+=2;
  229. a.set("data",4);
  230. tcp.store("key",s,t,a);
  231. unsigned keys,triggers;
  232. tcp.stats(keys,triggers);
  233. assert(keys==1);
  234. assert(triggers==1);
  235. s.clear();
  236. a.set("");
  237. assert(tcp.fetch("key",a,s)==true);
  238. assert(s.size()==1);
  239. assert(*(s.begin())=="key");
  240. assert(a.get()=="data");
  241. sleep(3);
  242. assert(tcp.fetch("key",a,s)==false);
  243. a.set("");
  244. a<<string("msg1");
  245. a<<string("msg2");
  246. time(&t);
  247. t+=50;
  248. s.clear();
  249. s.insert("a");
  250. s.insert("b");
  251. tcp.store("k",s,t,a);
  252. string x;
  253. assert(tcp.fetch_page("k",x,true)==true);
  254. assert(x=="msg2");
  255. assert(tcp.fetch_page("k",x,false)==true);
  256. assert(x=="msg1");
  257. a.set("");
  258. s.clear();
  259. assert(tcp.fetch("k",a,s)==true);
  260. assert(s.size()==3);
  261. set<string>::iterator ptr=s.begin();
  262. assert(*ptr++=="a");
  263. assert(*ptr++=="b");
  264. assert(*ptr++=="k");
  265. tcp.rise("a");
  266. assert(tcp.fetch("k",a,s)==false);
  267. a.set("Something");
  268. s.clear();
  269. tcp.store("bb",s,t,a);
  270. assert(tcp.fetch("xx",a,s)==false);
  271. assert(tcp.fetch("bb",a,s)==true);
  272. tcp.clear();
  273. assert(tcp.fetch("bb",a,s)==false);
  274. cout<<"Done... OK!\n";
  275. }
  276. catch(std::exception const &e) {
  277. cerr<<e.what()<<endl;
  278. }
  279. }
  280. #endif