1
0
mirror of https://github.com/haiwen/seafile-server.git synced 2025-06-27 23:46:48 +00:00
seafile-server/server/processors/heartbeat-proc.c
2016-08-19 13:54:16 +08:00

275 lines
7.6 KiB
C

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "common.h"
#include <ccnet/timer.h>
#include "seafile-session.h"
#include "heartbeat-proc.h"
/*
* Block sizes update algorithm:
*
* 1. When heartbeat starts, it send the list of all current blocks to monitor;
* 2. When a new block is sent to this chunk server, heartbeat will receive
* a signal from block manager. It will add the block metadata into
* priv->block_metadata_new queue. If more than 30 block metadata have been
* queued, heartbeat proc will send the list to monitor.
* 3. On an idle chunk server, it may take long time to queue 30 blocks.
* To keep the monitor up-to-date, a flush timer is scheduled to flush
* block info to monitor every 30 seconds.
*/
#define FLUSH_INTERVAL_MSEC 30 * 1000
#define SC_BLOCK_INFO "301"
#define SS_BLOCK_INFO "Block info"
/*
Master Slave
seafile-heartbeat
----------------------------->
OK
<-----------------------------
Block Info
----------------------------->
Block Info
----------------------------->
...
*/
typedef struct {
GList *block_metadata_old;
GList *block_metadata_new;
int new_blocks;
CcnetTimer *flush_timer;
} SeafileHeartbeatProcPriv;
#define GET_PRIV(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_HEARTBEAT_PROC, SeafileHeartbeatProcPriv))
#define USE_PRIV \
SeafileHeartbeatProcPriv *priv = GET_PRIV(processor);
G_DEFINE_TYPE (SeafileHeartbeatProc, seafile_heartbeat_proc, CCNET_TYPE_PROCESSOR)
static int start (CcnetProcessor *processor, int argc, char **argv);
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen);
static void *collect_block_sizes (void *vprocessor);
static void collect_block_sizes_done (CcnetProcessor *processor,
int status,
char *message);
static void on_block_added (SeafBlockManager *block_mgr,
const char *block_id,
void *vprocessor);
static int flush_block_sizes (void *vprocessor);
static void free_md_list (GList *md_list);
static void
release_resource(CcnetProcessor *processor)
{
USE_PRIV;
if (priv->block_metadata_old)
free_md_list (priv->block_metadata_old);
if (priv->block_metadata_new)
free_md_list (priv->block_metadata_new);
g_signal_handlers_disconnect_by_func (seaf->block_mgr, on_block_added, processor);
ccnet_timer_free (&priv->flush_timer);
CCNET_PROCESSOR_CLASS (seafile_heartbeat_proc_parent_class)->release_resource (processor);
}
static void
seafile_heartbeat_proc_class_init (SeafileHeartbeatProcClass *klass)
{
CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass);
proc_class->name = "heartbeat-proc";
proc_class->start = start;
proc_class->handle_response = handle_response;
proc_class->handle_thread_done = collect_block_sizes_done;
proc_class->release_resource = release_resource;
g_type_class_add_private (klass, sizeof (SeafileHeartbeatProcPriv));
}
static void
seafile_heartbeat_proc_init (SeafileHeartbeatProc *processor)
{
}
static int
start (CcnetProcessor *processor, int argc, char **argv)
{
char buf[256];
snprintf (buf, sizeof(buf), "remote %s seafile-heartbeat",
processor->peer_id);
ccnet_processor_send_request (processor, buf);
return 0;
}
static void
handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen)
{
USE_PRIV;
int rc;
if (strncmp (code, SC_OK, 3) == 0) {
rc = ccnet_processor_thread_create (processor,
collect_block_sizes,
NULL);
if (rc < 0) {
g_warning ("[heartbeat] failed to create thread.\n");
ccnet_processor_done (processor, FALSE);
}
g_signal_connect (seaf->block_mgr, "block-added",
(GCallback)on_block_added,
processor);
priv->flush_timer = ccnet_timer_new (flush_block_sizes,
processor,
FLUSH_INTERVAL_MSEC);
} else {
g_warning ("[heartbeat] Bad response: %s %s\n", code, code_msg);
ccnet_processor_done (processor, FALSE);
}
}
static void
send_block_sizes (CcnetProcessor *processor, GList *metadata)
{
char buf[2048];
char *ptr = buf;
int count = 0, n;
GList *md_list = metadata;
BlockMetadata *md;
while (md_list) {
md = md_list->data;
md_list = g_list_delete_link (md_list, md_list);
n = snprintf (ptr, 60, "%s %u\n", md->id, md->size);
ptr += n;
if (++count == 30) {
ccnet_processor_send_update (processor,
SC_BLOCK_INFO, SS_BLOCK_INFO,
buf, (ptr - buf) + 1);
count = 0;
ptr = buf;
}
g_free (md);
}
if (count) {
ccnet_processor_send_update (processor,
SC_BLOCK_INFO, SS_BLOCK_INFO,
buf, (ptr - buf) + 1);
}
}
static void *
collect_block_sizes (void *vprocessor)
{
CcnetProcessor *processor = vprocessor;
GList *metadata_list;
USE_PRIV;
metadata_list = seaf_block_manager_get_all_block_metadata (seaf->block_mgr);
/* if (!metadata_list) { */
/* ccnet_processor_thread_done (processor, -1, NULL); */
/* return NULL; */
/* } */
priv->block_metadata_old = metadata_list;
ccnet_processor_thread_done (processor, 0, NULL);
return NULL;
}
static void
collect_block_sizes_done (CcnetProcessor *processor,
int status,
char *message)
{
USE_PRIV;
if (status == 0) {
g_message ("[hearbeat] collected block sizes on start.\n");
send_block_sizes (processor, priv->block_metadata_old);
priv->block_metadata_old = NULL;
} else {
g_warning ("Failed to collect block sizes.\n");
ccnet_processor_done (processor, FALSE);
}
}
static void
on_block_added (SeafBlockManager *block_mgr,
const char *block_id,
void *vprocessor)
{
CcnetProcessor *processor = vprocessor;
BlockMetadata *md;
USE_PRIV;
md = seaf_block_manager_stat_block (block_mgr, block_id);
if (!md) {
g_warning ("[heartbeat] Failed to stat block %s\n", block_id);
return;
}
g_message ("Queue block %s, size is %u\n", block_id, md->size);
priv->block_metadata_new = g_list_prepend (priv->block_metadata_new, md);
if (++priv->new_blocks == 30) {
send_block_sizes (processor, priv->block_metadata_new);
priv->block_metadata_new = NULL;
priv->new_blocks = 0;
}
}
static int
flush_block_sizes (void *vprocessor)
{
CcnetProcessor *processor = vprocessor;
USE_PRIV;
if (priv->new_blocks != 0) {
g_message ("Flushing %u blocks to monitor.\n", priv->new_blocks);
send_block_sizes (processor, priv->block_metadata_new);
priv->block_metadata_new = NULL;
priv->new_blocks = 0;
}
return 1;
}
static void
free_md_list (GList *md_list)
{
BlockMetadata *md;
while (md_list) {
md = md_list->data;
md_list = g_list_delete_link (md_list, md_list);
g_free (md);
}
}