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.

binlog.c 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  1. /*
  2. * Copyright (c) 2009-2012, Vsevolod Stakhov
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
  14. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  15. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  16. * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
  17. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  18. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  19. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  20. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  21. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  22. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  23. */
  24. #include "config.h"
  25. #include "binlog.h"
  26. #include "cfg_file.h"
  27. #include "tokenizers.h"
  28. #define BINLOG_SUFFIX ".binlog"
  29. #define BACKUP_SUFFIX ".old"
  30. #define VALID_MAGIC { 'r', 's', 'l' }
  31. #define VALID_VERSION { '1', '0' }
  32. static GHashTable *binlog_opened = NULL;
  33. static rspamd_mempool_t *binlog_pool = NULL;
  34. static gboolean
  35. binlog_write_header (struct rspamd_binlog *log)
  36. {
  37. struct rspamd_binlog_header header = {
  38. .magic = VALID_MAGIC,
  39. .version = VALID_VERSION,
  40. .padding = { '\0', '\0' },
  41. };
  42. header.create_time = time (NULL);
  43. rspamd_file_lock (log->fd, FALSE);
  44. if (write (log->fd, &header, sizeof (struct rspamd_binlog_header)) == -1) {
  45. msg_warn ("cannot write file %s, error %d, %s",
  46. log->filename,
  47. errno,
  48. strerror (errno));
  49. return FALSE;
  50. }
  51. memcpy (&log->header, &header, sizeof (struct rspamd_binlog_header));
  52. /* Metaindex */
  53. log->metaindex = g_malloc (sizeof (struct rspamd_binlog_metaindex));
  54. bzero (log->metaindex, sizeof (struct rspamd_binlog_metaindex));
  55. /* Offset to metaindex */
  56. log->metaindex->indexes[0] = sizeof (struct rspamd_binlog_metaindex) +
  57. sizeof (struct rspamd_binlog_header);
  58. if (write (log->fd, log->metaindex,
  59. sizeof (struct rspamd_binlog_metaindex)) == -1) {
  60. g_free (log->metaindex);
  61. msg_warn ("cannot write file %s, error %d, %s",
  62. log->filename,
  63. errno,
  64. strerror (errno));
  65. rspamd_file_unlock (log->fd, FALSE);
  66. return FALSE;
  67. }
  68. /* Alloc, write, mmap */
  69. log->cur_idx = g_malloc (sizeof (struct rspamd_index_block));
  70. bzero (log->cur_idx, sizeof (struct rspamd_index_block));
  71. if (write (log->fd, log->cur_idx,
  72. sizeof (struct rspamd_index_block)) == -1) {
  73. g_free (log->cur_idx);
  74. msg_warn ("cannot write file %s, error %d, %s",
  75. log->filename,
  76. errno,
  77. strerror (errno));
  78. rspamd_file_unlock (log->fd, FALSE);
  79. return FALSE;
  80. }
  81. rspamd_file_unlock (log->fd, FALSE);
  82. return TRUE;
  83. }
  84. static gboolean
  85. binlog_check_file (struct rspamd_binlog *log)
  86. {
  87. static gchar valid_magic[] = VALID_MAGIC, valid_version[] = VALID_VERSION;
  88. if (read (log->fd, &log->header,
  89. sizeof (struct rspamd_binlog_header)) !=
  90. sizeof (struct rspamd_binlog_header)) {
  91. msg_warn ("cannot read file %s, error %d, %s",
  92. log->filename,
  93. errno,
  94. strerror (errno));
  95. return FALSE;
  96. }
  97. /* Now check all fields */
  98. if (memcmp (&log->header.magic, valid_magic, sizeof (valid_magic)) != 0 ||
  99. memcmp (&log->header.version, valid_version,
  100. sizeof (valid_version)) != 0) {
  101. msg_warn ("cannot validate file %s");
  102. return FALSE;
  103. }
  104. /* Now mmap metaindex and current index */
  105. if (log->metaindex == NULL) {
  106. log->metaindex = g_malloc (sizeof (struct rspamd_binlog_metaindex));
  107. }
  108. if ((read (log->fd, log->metaindex,
  109. sizeof (struct rspamd_binlog_metaindex))) !=
  110. sizeof (struct rspamd_binlog_metaindex)) {
  111. msg_warn ("cannot read metaindex of file %s, error %d, %s",
  112. log->filename,
  113. errno,
  114. strerror (errno));
  115. return FALSE;
  116. }
  117. /* Current index */
  118. if (log->cur_idx == NULL) {
  119. log->cur_idx = g_malloc (sizeof (struct rspamd_index_block));
  120. }
  121. if (lseek (log->fd, log->metaindex->indexes[log->metaindex->last_index],
  122. SEEK_SET) == -1) {
  123. msg_info ("cannot seek in file: %s, error: %s",
  124. log->filename,
  125. strerror (errno));
  126. return FALSE;
  127. }
  128. if ((read (log->fd, log->cur_idx,
  129. sizeof (struct rspamd_index_block))) !=
  130. sizeof (struct rspamd_index_block)) {
  131. msg_warn ("cannot read index in file %s, error %d, %s",
  132. log->filename,
  133. errno,
  134. strerror (errno));
  135. return FALSE;
  136. }
  137. log->cur_seq = log->metaindex->last_index * BINLOG_IDX_LEN +
  138. log->cur_idx->last_index;
  139. log->cur_time = log->cur_idx->indexes[log->cur_idx->last_index].time;
  140. return TRUE;
  141. }
  142. static gboolean
  143. binlog_create (struct rspamd_binlog *log)
  144. {
  145. if ((log->fd =
  146. open (log->filename, O_RDWR | O_TRUNC | O_CREAT,
  147. S_IWUSR | S_IRUSR)) == -1) {
  148. msg_info ("cannot create file %s, error %d, %s",
  149. log->filename,
  150. errno,
  151. strerror (errno));
  152. return FALSE;
  153. }
  154. return binlog_write_header (log);
  155. }
  156. static gboolean
  157. binlog_open_real (struct rspamd_binlog *log)
  158. {
  159. if ((log->fd = open (log->filename, O_RDWR)) == -1) {
  160. msg_info ("cannot open file %s, error %d, %s",
  161. log->filename,
  162. errno,
  163. strerror (errno));
  164. return FALSE;
  165. }
  166. return binlog_check_file (log);
  167. }
  168. struct rspamd_binlog *
  169. binlog_open (rspamd_mempool_t *pool,
  170. const gchar *path,
  171. time_t rotate_time,
  172. gint rotate_jitter)
  173. {
  174. struct rspamd_binlog *new;
  175. gint len = strlen (path);
  176. struct stat st;
  177. new = rspamd_mempool_alloc0 (pool, sizeof (struct rspamd_binlog));
  178. new->pool = pool;
  179. new->rotate_time = rotate_time;
  180. new->fd = -1;
  181. if (rotate_time) {
  182. new->rotate_jitter = g_random_int_range (0, rotate_jitter);
  183. }
  184. new->filename = rspamd_mempool_alloc (pool, len + sizeof (BINLOG_SUFFIX));
  185. rspamd_strlcpy (new->filename, path, len + 1);
  186. rspamd_strlcpy (new->filename + len, BINLOG_SUFFIX, sizeof (BINLOG_SUFFIX));
  187. if (stat (new->filename, &st) == -1) {
  188. /* Check errno to check whether we should create this file */
  189. if (errno != ENOENT) {
  190. msg_err ("cannot stat file: %s, error %s", new->filename,
  191. strerror (errno));
  192. return NULL;
  193. }
  194. else {
  195. /* In case of ENOENT try to create binlog */
  196. if (!binlog_create (new)) {
  197. return NULL;
  198. }
  199. }
  200. }
  201. else {
  202. /* Try to open binlog */
  203. if (!binlog_open_real (new)) {
  204. return NULL;
  205. }
  206. }
  207. return new;
  208. }
  209. void
  210. binlog_close (struct rspamd_binlog *log)
  211. {
  212. if (log) {
  213. if (log->metaindex) {
  214. g_free (log->metaindex);
  215. }
  216. if (log->cur_idx) {
  217. g_free (log->cur_idx);
  218. }
  219. close (log->fd);
  220. }
  221. }
  222. static gboolean
  223. binlog_tree_callback (gpointer key, gpointer value, gpointer data)
  224. {
  225. token_node_t *node = key;
  226. struct rspamd_binlog *log = data;
  227. struct rspamd_binlog_element elt;
  228. elt.h1 = node->h1;
  229. elt.h2 = node->h2;
  230. elt.value = node->value;
  231. if (write (log->fd, &elt, sizeof (elt)) == -1) {
  232. msg_info ("cannot write token to file: %s, error: %s",
  233. log->filename,
  234. strerror (errno));
  235. return TRUE;
  236. }
  237. return FALSE;
  238. }
  239. static gboolean
  240. write_binlog_tree (struct rspamd_binlog *log, GTree *nodes)
  241. {
  242. off_t seek;
  243. struct rspamd_binlog_index *idx;
  244. rspamd_file_lock (log->fd, FALSE);
  245. log->cur_seq++;
  246. /* Seek to end of file */
  247. if ((seek = lseek (log->fd, 0, SEEK_END)) == -1) {
  248. rspamd_file_unlock (log->fd, FALSE);
  249. msg_info ("cannot seek in file: %s, error: %s",
  250. log->filename,
  251. strerror (errno));
  252. return FALSE;
  253. }
  254. /* Now write all nodes to file */
  255. g_tree_foreach (nodes, binlog_tree_callback, (gpointer)log);
  256. /* Write index */
  257. idx = &log->cur_idx->indexes[log->cur_idx->last_index];
  258. idx->seek = seek;
  259. idx->time = (guint64)time (NULL);
  260. log->cur_time = idx->time;
  261. idx->len = g_tree_nnodes (nodes) * sizeof (struct rspamd_binlog_element);
  262. if (lseek (log->fd, log->metaindex->indexes[log->metaindex->last_index],
  263. SEEK_SET) == -1) {
  264. rspamd_file_unlock (log->fd, FALSE);
  265. msg_info (
  266. "cannot seek in file: %s, error: %s, seek: %L, op: insert index",
  267. log->filename,
  268. strerror (errno),
  269. log->metaindex->indexes[log->metaindex->last_index]);
  270. return FALSE;
  271. }
  272. log->cur_idx->last_index++;
  273. if (write (log->fd, log->cur_idx,
  274. sizeof (struct rspamd_index_block)) == -1) {
  275. rspamd_file_unlock (log->fd, FALSE);
  276. msg_info ("cannot write index to file: %s, error: %s",
  277. log->filename,
  278. strerror (errno));
  279. return FALSE;
  280. }
  281. rspamd_file_unlock (log->fd, FALSE);
  282. return TRUE;
  283. }
  284. static gboolean
  285. create_new_metaindex_block (struct rspamd_binlog *log)
  286. {
  287. off_t seek;
  288. rspamd_file_lock (log->fd, FALSE);
  289. log->metaindex->last_index++;
  290. /* Seek to end of file */
  291. if ((seek = lseek (log->fd, 0, SEEK_END)) == -1) {
  292. rspamd_file_unlock (log->fd, FALSE);
  293. msg_info ("cannot seek in file: %s, error: %s",
  294. log->filename,
  295. strerror (errno));
  296. return FALSE;
  297. }
  298. if (write (log->fd, log->cur_idx,
  299. sizeof (struct rspamd_index_block)) == -1) {
  300. rspamd_file_unlock (log->fd, FALSE);
  301. g_free (log->cur_idx);
  302. msg_warn ("cannot write file %s, error %d, %s",
  303. log->filename,
  304. errno,
  305. strerror (errno));
  306. return FALSE;
  307. }
  308. /* Offset to metaindex */
  309. log->metaindex->indexes[log->metaindex->last_index] = seek;
  310. /* Overwrite all metaindexes */
  311. if (lseek (log->fd, sizeof (struct rspamd_binlog_header), SEEK_SET) == -1) {
  312. rspamd_file_unlock (log->fd, FALSE);
  313. msg_info ("cannot seek in file: %s, error: %s",
  314. log->filename,
  315. strerror (errno));
  316. return FALSE;
  317. }
  318. if (write (log->fd, log->metaindex,
  319. sizeof (struct rspamd_binlog_metaindex)) == -1) {
  320. rspamd_file_unlock (log->fd, FALSE);
  321. msg_info ("cannot write metaindex in file: %s, error: %s",
  322. log->filename,
  323. strerror (errno));
  324. return FALSE;
  325. }
  326. bzero (log->cur_idx, sizeof (struct rspamd_index_block));
  327. rspamd_file_unlock (log->fd, FALSE);
  328. return TRUE;
  329. }
  330. static gboolean
  331. maybe_rotate_binlog (struct rspamd_binlog *log)
  332. {
  333. guint64 now = time (NULL);
  334. if (log->rotate_time &&
  335. ((now - log->header.create_time) >
  336. (guint)(log->rotate_time + log->rotate_jitter))) {
  337. return TRUE;
  338. }
  339. return FALSE;
  340. }
  341. static gboolean
  342. rotate_binlog (struct rspamd_binlog *log)
  343. {
  344. gchar *backup_name;
  345. struct stat st;
  346. rspamd_file_lock (log->fd, FALSE);
  347. /* Unmap mapped fragments */
  348. if (log->metaindex) {
  349. g_free (log->metaindex);
  350. log->metaindex = NULL;
  351. }
  352. if (log->cur_idx) {
  353. g_free (log->cur_idx);
  354. log->cur_idx = NULL;
  355. }
  356. /* Format backup name */
  357. backup_name = g_strdup_printf ("%s.%s", log->filename, BACKUP_SUFFIX);
  358. if (stat (backup_name, &st) != -1) {
  359. msg_info ("replace old %s", backup_name);
  360. unlink (backup_name);
  361. }
  362. rename (log->filename, backup_name);
  363. g_free (backup_name);
  364. /* XXX: maybe race condition here */
  365. rspamd_file_unlock (log->fd, FALSE);
  366. close (log->fd);
  367. return binlog_create (log);
  368. }
  369. gboolean
  370. binlog_insert (struct rspamd_binlog *log, GTree *nodes)
  371. {
  372. off_t seek;
  373. if (!log || !log->metaindex || !log->cur_idx || !nodes) {
  374. msg_info ("improperly opened binlog: %s",
  375. log != NULL ? log->filename : "unknown");
  376. return FALSE;
  377. }
  378. if (maybe_rotate_binlog (log)) {
  379. if (!rotate_binlog (log)) {
  380. return FALSE;
  381. }
  382. }
  383. /* First of all try to place new tokens in current index */
  384. if (log->cur_idx->last_index < BINLOG_IDX_LEN) {
  385. /* All is ok */
  386. return write_binlog_tree (log, nodes);
  387. }
  388. /* Current index table is all busy, try to allocate new index */
  389. /* Check metaindex free space */
  390. if (log->metaindex->last_index < METAINDEX_LEN) {
  391. /* Create new index block */
  392. if ((seek = lseek (log->fd, 0, SEEK_END)) == (off_t)-1) {
  393. msg_info ("cannot seek in file: %s, error: %s",
  394. log->filename,
  395. strerror (errno));
  396. return FALSE;
  397. }
  398. if (!create_new_metaindex_block (log)) {
  399. return FALSE;
  400. }
  401. return write_binlog_tree (log, nodes);
  402. }
  403. /* All binlog is filled, we need to rotate it forcefully */
  404. if (!rotate_binlog (log)) {
  405. return FALSE;
  406. }
  407. return write_binlog_tree (log, nodes);
  408. }
  409. gboolean
  410. binlog_sync (struct rspamd_binlog *log,
  411. guint64 from_rev,
  412. guint64 *from_time,
  413. GByteArray **rep)
  414. {
  415. guint32 metaindex_num;
  416. struct rspamd_index_block *idxb;
  417. struct rspamd_binlog_index *idx;
  418. gboolean idx_mapped = FALSE, res = TRUE, is_first = FALSE;
  419. if (!log || !log->metaindex || !log->cur_idx) {
  420. msg_info ("improperly opened binlog: %s",
  421. log != NULL ? log->filename : "unknown");
  422. return FALSE;
  423. }
  424. if (*rep == NULL) {
  425. *rep = g_malloc (sizeof (GByteArray));
  426. is_first = TRUE;
  427. }
  428. else {
  429. /* Unmap old fragment */
  430. g_free ((*rep)->data);
  431. }
  432. if (from_rev == log->cur_seq) {
  433. /* Last record */
  434. *rep = NULL;
  435. return FALSE;
  436. }
  437. else if (from_rev > log->cur_seq) {
  438. /* Slave has more actual copy, write this to log and abort sync */
  439. msg_warn (
  440. "slave has more recent revision of statfile %s: %uL and our is: %uL",
  441. log->filename,
  442. from_rev,
  443. log->cur_seq);
  444. *rep = NULL;
  445. *from_time = 0;
  446. return FALSE;
  447. }
  448. metaindex_num = from_rev / BINLOG_IDX_LEN;
  449. /* First of all try to find this revision */
  450. if (metaindex_num > log->metaindex->last_index) {
  451. return FALSE;
  452. }
  453. else if (metaindex_num != log->metaindex->last_index) {
  454. /* Need to remap index block */
  455. rspamd_file_lock (log->fd, FALSE);
  456. idxb = g_malloc (sizeof (struct rspamd_index_block));
  457. idx_mapped = TRUE;
  458. if (lseek (log->fd, log->metaindex->indexes[metaindex_num],
  459. SEEK_SET) == -1) {
  460. rspamd_file_unlock (log->fd, FALSE);
  461. msg_warn ("cannot seek file %s, error %d, %s",
  462. log->filename,
  463. errno,
  464. strerror (errno));
  465. res = FALSE;
  466. goto end;
  467. }
  468. if ((read (log->fd, idxb,
  469. sizeof (struct rspamd_index_block))) !=
  470. sizeof (struct rspamd_index_block)) {
  471. rspamd_file_unlock (log->fd, FALSE);
  472. msg_warn ("cannot read index from file %s, error %d, %s",
  473. log->filename,
  474. errno,
  475. strerror (errno));
  476. res = FALSE;
  477. goto end;
  478. }
  479. rspamd_file_unlock (log->fd, FALSE);
  480. }
  481. else {
  482. idxb = log->cur_idx;
  483. }
  484. /* Now check specified index */
  485. idx = &idxb->indexes[from_rev % BINLOG_IDX_LEN];
  486. if (is_first && idx->time != *from_time) {
  487. res = FALSE;
  488. *from_time = 0;
  489. goto end;
  490. }
  491. else {
  492. *from_time = idx->time;
  493. }
  494. /* Now fill reply structure */
  495. (*rep)->len = idx->len;
  496. /* Read result */
  497. msg_info (
  498. "update from binlog '%s' from revision: %uL to revision %uL size is %uL",
  499. log->filename,
  500. from_rev,
  501. log->cur_seq,
  502. idx->len);
  503. if (lseek (log->fd, idx->seek, SEEK_SET) == -1) {
  504. msg_warn ("cannot seek file %s, error %d, %s",
  505. log->filename,
  506. errno,
  507. strerror (errno));
  508. res = FALSE;
  509. goto end;
  510. }
  511. (*rep)->data = g_malloc (idx->len);
  512. if ((read (log->fd, (*rep)->data, idx->len)) != (ssize_t)idx->len) {
  513. msg_warn ("cannot read file %s, error %d, %s",
  514. log->filename,
  515. errno,
  516. strerror (errno));
  517. res = FALSE;
  518. goto end;
  519. }
  520. end:
  521. if (idx_mapped) {
  522. g_free (idxb);
  523. }
  524. return res;
  525. }
  526. static gboolean
  527. maybe_init_static (void)
  528. {
  529. if (!binlog_opened) {
  530. binlog_opened = g_hash_table_new (g_direct_hash, g_direct_equal);
  531. if (!binlog_opened) {
  532. return FALSE;
  533. }
  534. }
  535. if (!binlog_pool) {
  536. binlog_pool = rspamd_mempool_new (rspamd_mempool_suggest_size ());
  537. if (!binlog_pool) {
  538. return FALSE;
  539. }
  540. }
  541. return TRUE;
  542. }
  543. gboolean
  544. maybe_write_binlog (struct rspamd_classifier_config *ccf,
  545. struct rspamd_statfile_config *st,
  546. stat_file_t *file,
  547. GTree *nodes)
  548. {
  549. struct rspamd_binlog *log;
  550. if (ccf == NULL) {
  551. return FALSE;
  552. }
  553. if (st == NULL || nodes == NULL || st->binlog == NULL ||
  554. st->binlog->affinity != AFFINITY_MASTER) {
  555. return FALSE;
  556. }
  557. if (!maybe_init_static ()) {
  558. return FALSE;
  559. }
  560. if ((log = g_hash_table_lookup (binlog_opened, st)) == NULL) {
  561. if ((log =
  562. binlog_open (binlog_pool, st->path, st->binlog->rotate_time,
  563. st->binlog->rotate_time / 2)) != NULL) {
  564. g_hash_table_insert (binlog_opened, st, log);
  565. }
  566. else {
  567. return FALSE;
  568. }
  569. }
  570. if (binlog_insert (log, nodes)) {
  571. msg_info ("set new revision of statfile %s: %uL",
  572. st->symbol,
  573. log->cur_seq);
  574. (void)statfile_set_revision (file, log->cur_seq, log->cur_time);
  575. return TRUE;
  576. }
  577. return FALSE;
  578. }
  579. struct rspamd_binlog *
  580. get_binlog_by_statfile (struct rspamd_statfile_config *st)
  581. {
  582. struct rspamd_binlog *log;
  583. if (st == NULL || st->binlog == NULL || st->binlog->affinity !=
  584. AFFINITY_MASTER) {
  585. return NULL;
  586. }
  587. if (!maybe_init_static ()) {
  588. return NULL;
  589. }
  590. if ((log = g_hash_table_lookup (binlog_opened, st)) == NULL) {
  591. if ((log =
  592. binlog_open (binlog_pool, st->path, st->binlog->rotate_time,
  593. st->binlog->rotate_time / 2)) != NULL) {
  594. g_hash_table_insert (binlog_opened, st, log);
  595. }
  596. else {
  597. return NULL;
  598. }
  599. }
  600. return log;
  601. }