/pool.c

http://github.com/nicolasff/webdis · C · 181 lines · 133 code · 40 blank · 8 comment · 29 complexity · a48c0574a82a566a62d3879ea4907f54 MD5 · raw file

  1. #include "pool.h"
  2. #include "worker.h"
  3. #include "conf.h"
  4. #include "server.h"
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <event.h>
  8. #include <hiredis/adapters/libevent.h>
  9. static void
  10. pool_schedule_reconnect(struct pool* p);
  11. struct pool *
  12. pool_new(struct worker *w, int count) {
  13. struct pool *p = calloc(1, sizeof(struct pool));
  14. p->count = count;
  15. p->ac = calloc(count, sizeof(redisAsyncContext*));
  16. p->w = w;
  17. p->cfg = w->s->cfg;
  18. return p;
  19. }
  20. void
  21. pool_free_context(redisAsyncContext *ac) {
  22. if (ac) {
  23. redisAsyncDisconnect(ac);
  24. redisAsyncFree(ac);
  25. }
  26. }
  27. static void
  28. pool_on_connect(const redisAsyncContext *ac, int status) {
  29. struct pool *p = ac->data;
  30. int i = 0;
  31. if(!p || status == REDIS_ERR || ac->err) {
  32. if (p) {
  33. pool_schedule_reconnect(p);
  34. }
  35. return;
  36. }
  37. /* connected to redis! */
  38. /* add to pool */
  39. for(i = 0; i < p->count; ++i) {
  40. if(p->ac[i] == NULL) {
  41. p->ac[i] = ac;
  42. return;
  43. }
  44. }
  45. }
  46. struct pool_reconnect {
  47. struct event ev;
  48. struct pool *p;
  49. struct timeval tv;
  50. };
  51. static void
  52. pool_can_connect(int fd, short event, void *ptr) {
  53. struct pool_reconnect *pr = ptr;
  54. struct pool *p = pr->p;
  55. (void)fd;
  56. (void)event;
  57. free(pr);
  58. pool_connect(p, p->cfg->database, 1);
  59. }
  60. static void
  61. pool_schedule_reconnect(struct pool *p) {
  62. struct pool_reconnect *pr = malloc(sizeof(struct pool_reconnect));
  63. pr->p = p;
  64. pr->tv.tv_sec = 0;
  65. pr->tv.tv_usec = 100*1000; /* 0.1 sec*/
  66. evtimer_set(&pr->ev, pool_can_connect, pr);
  67. event_base_set(p->w->base, &pr->ev);
  68. evtimer_add(&pr->ev, &pr->tv);
  69. }
  70. static void
  71. pool_on_disconnect(const redisAsyncContext *ac, int status) {
  72. struct pool *p = ac->data;
  73. int i = 0;
  74. if (status != REDIS_OK) {
  75. /* fprintf(stderr, "Error: %s\n", ac->errstr); */
  76. }
  77. if(p == NULL) { /* no need to clean anything here. */
  78. return;
  79. }
  80. /* remove from the pool */
  81. for(i = 0; i < p->count; ++i) {
  82. if(p->ac[i] == ac) {
  83. p->ac[i] = NULL;
  84. break;
  85. }
  86. }
  87. /* schedule reconnect */
  88. pool_schedule_reconnect(p);
  89. }
  90. /**
  91. * Create new connection.
  92. */
  93. redisAsyncContext *
  94. pool_connect(struct pool *p, int db_num, int attach) {
  95. struct redisAsyncContext *ac;
  96. if(p->cfg->redis_host[0] == '/') { /* unix socket */
  97. ac = redisAsyncConnectUnix(p->cfg->redis_host);
  98. } else {
  99. ac = redisAsyncConnect(p->cfg->redis_host, p->cfg->redis_port);
  100. }
  101. if(attach) {
  102. ac->data = p;
  103. } else {
  104. ac->data = NULL;
  105. }
  106. if(ac->err) {
  107. char msg[] = "Connection failed: %s";
  108. size_t errlen = strlen(ac->errstr);
  109. char *err = malloc(sizeof(msg) + errlen);
  110. if (err) {
  111. size_t sz = sprintf(err, msg, ac->errstr);
  112. slog(p->w->s, WEBDIS_ERROR, err, sz);
  113. free(err);
  114. }
  115. redisAsyncFree(ac);
  116. pool_schedule_reconnect(p);
  117. return NULL;
  118. }
  119. redisLibeventAttach(ac, p->w->base);
  120. redisAsyncSetConnectCallback(ac, pool_on_connect);
  121. redisAsyncSetDisconnectCallback(ac, pool_on_disconnect);
  122. if(p->cfg->redis_auth) { /* authenticate. */
  123. redisAsyncCommand(ac, NULL, NULL, "AUTH %s", p->cfg->redis_auth);
  124. }
  125. if(db_num) { /* change database. */
  126. redisAsyncCommand(ac, NULL, NULL, "SELECT %d", db_num);
  127. }
  128. return ac;
  129. }
  130. const redisAsyncContext *
  131. pool_get_context(struct pool *p) {
  132. int orig = p->cur++;
  133. do {
  134. p->cur++;
  135. p->cur %= p->count;
  136. if(p->ac[p->cur] != NULL) {
  137. return p->ac[p->cur];
  138. }
  139. } while(p->cur != orig);
  140. return NULL;
  141. }