static int node_binlog_add(merlin_node *node, merlin_event *pkt) { int result; /* * we skip stashing some packet types in the binlog. Typically * those that get generated immediately upon reconnect anyway * since they would just cause unnecessary overhead and might * trigger a lot of unnecessary actions if stashed. */ if (pkt->hdr.type == CTRL_PACKET) { if (pkt->hdr.code == CTRL_ACTIVE || pkt->hdr.code == CTRL_INACTIVE) return 0; } if (!node->binlog) { char *path; /* +20 to safely accommodate for "/.module.binlog\0" */ path = calloc(1, strlen(binlog_dir) + strlen(node->name) + 20); sprintf(path, "%s/%s.%s.binlog", binlog_dir, is_module ? "module" : "daemon", node->name); linfo("Creating binary backlog for %s. On-disk location: %s", node->name, path); /* 10MB in memory, 100MB on disk */ node->binlog = binlog_create(path, 10 << 20, 100 << 20, BINLOG_UNLINK); if (!node->binlog) { lerr("Failed to create binary backlog for %s: %s", node->name, strerror(errno)); return -1; } free(path); } result = binlog_add(node->binlog, pkt, packet_size(pkt)); if (result < 0) { binlog_wipe(node->binlog, BINLOG_UNLINK); /* XXX should mark node as unsynced here */ node->stats.events.dropped += node->stats.events.logged + 1; node->stats.bytes.dropped += node->stats.bytes.logged + packet_size(pkt); node->stats.events.logged = 0; node->stats.bytes.logged = 0; } else { node->stats.events.logged++; node->stats.bytes.logged += packet_size(pkt); } node_log_event_count(node, 0); return result; }
void binlog_destroy(binlog *bl, int flags) { if (!bl) return; binlog_wipe(bl, flags); if (bl->path) { free(bl->path); bl->path = NULL; } free(bl); }
int node_send_binlog(merlin_node *node, merlin_event *pkt) { merlin_event *temp_pkt; uint len; ldebug("Emptying backlog for %s", node->name); while (io_write_ok(node->sock, 10) && !binlog_read(node->binlog, (void **)&temp_pkt, &len)) { int result; if (!temp_pkt || packet_size(temp_pkt) != (int)len || !len || !packet_size(temp_pkt) || packet_size(temp_pkt) > MAX_PKT_SIZE) { if (!temp_pkt) { lerr("BACKLOG: binlog returned 0 but presented no data"); } else { lerr("BACKLOG: binlog returned a packet claiming to be of size %d", packet_size(temp_pkt)); } lerr("BACKLOG: binlog claims the data length is %u", len); lerr("BACKLOG: wiping backlog. %s is now out of sync", node->name); binlog_wipe(node->binlog, BINLOG_UNLINK); return -1; } errno = 0; result = node_send(node, temp_pkt, packet_size(temp_pkt), MSG_DONTWAIT); /* keep going while we successfully send something */ if (result == packet_size(temp_pkt)) { node->stats.events.sent++; node->stats.events.logged--; node->stats.bytes.logged -= packet_size(temp_pkt); /* * binlog duplicates the memory, so we must release it * when we've sent and counted it */ free(temp_pkt); continue; } /* * we can recover from total failures by unread()'ing * the entry we just read and then adding the new entry * to the binlog in the hopes that we'll get a * connection up and running again before it's time to * send more data to this node */ if (result <= 0) { if (!binlog_unread(node->binlog, temp_pkt, len)) { if (pkt) return node_binlog_add(node, pkt); return 0; } else { free(temp_pkt); } } /* * we wrote a partial event or failed to unread the event, * so this node is now out of sync. We must wipe the binlog * and possibly mark this node as being out of sync. */ lerr("Wiping binlog for %s node %s", node_type(node), node->name); binlog_wipe(node->binlog, BINLOG_UNLINK); if (pkt) { node->stats.events.dropped += node->stats.events.logged + 1; node->stats.bytes.dropped += node->stats.bytes.logged + packet_size(pkt); } node_log_event_count(node, 0); return -1; } return 0; }