文档章节

LVM源码分析2-libdaemon

LastRitter
 LastRitter
发布于 2017/09/08 23:21
字数 1390
阅读 55
收藏 0

LVM的libdaemon库实现了守护进程与命令工具之间使用UNIX本地套接字进行CS通信的基础模型。

报文

配置树结构

$ cat libdm/libdevmapper.h
...

typedef enum {
	DM_CFG_INT,
	DM_CFG_FLOAT,
	DM_CFG_STRING,
	DM_CFG_EMPTY_ARRAY
} dm_config_value_type_t;

struct dm_config_value {
	dm_config_value_type_t type;

	union {
		int64_t i;
		float f;
		double d;       	/* Unused. */
		const char *str;
	} v;

	struct dm_config_value *next;	/* For arrays */
	uint32_t format_flags;
};

struct dm_config_node {
	const char *key;
	struct dm_config_node *parent, *sib, *child;
	struct dm_config_value *v;
	int id;
};

struct dm_config_tree {
	struct dm_config_node *root;
	struct dm_config_tree *cascade;
	struct dm_pool *mem;
	void *custom;
};

...

请求和响应报文

服务端:

$ cat libdaemon/server/daemon-server.h
...

typedef struct {
	struct dm_config_tree *cft;
	struct buffer buffer;
} request;

typedef struct {
	int error;
	struct dm_config_tree *cft;
	struct buffer buffer;
} response;

...

客户端:

$ cat libdaemon/client/daemon-client.h
...

typedef struct {
	struct buffer buffer;
	/*
	 * The request looks like this:
	 *    request = "id"
	 *    arg_foo = "something"
	 *    arg_bar = 3
	 *    arg_wibble {
	 *        something_special = "here"
	 *        amount = 75
	 *        knobs = [ "twiddle", "tweak" ]
	 *    }
	 */
	struct dm_config_tree *cft;
} daemon_request;

typedef struct {
	int error; /* 0 for success */
	struct buffer buffer;
	struct dm_config_tree *cft; /* parsed reply, if available */
} daemon_reply;

...

服务端

守护服务状态

$ cat libdaemon/server/daemon-server.h
...

typedef struct daemon_state {
	/*
	 * The maximal stack size for individual daemon threads. This is
	 * essential for daemons that need to be locked into memory, since
	 * pthread's default is 10M per thread.
	 */
	int thread_stack_size;

	/* Flags & attributes affecting the behaviour of the daemon. */
	unsigned avoid_oom:1;
	unsigned foreground:1;
	const char *name;
	const char *pidfile;
	const char *socket_path;
	const char *protocol;
	int protocol_version;

	handle_request handler;
	int (*daemon_init)(struct daemon_state *st);
	int (*daemon_fini)(struct daemon_state *st);
	int (*daemon_main)(struct daemon_state *st);

	/* Global runtime info maintained by the framework. */
	int socket_fd;

	log_state *log;
	struct thread_state *threads;

	/* suport for shutdown on idle */
	daemon_idle *idle;

	void *private; /* the global daemon state */
} daemon_state;

...

守护服务启动、接管和停止

$ cat libdaemon/server/daemon-server.h
...

/*
 * Start serving the requests. This does all the daemonisation, socket setup
 * work and so on. This function takes over the process, and upon failure, it
 * will terminate execution. It may be called at most once.
 */
void daemon_start(daemon_state s);

/*
 * Take over from an already running daemon. This function handles connecting
 * to the running daemon and telling it we are going to take over. The takeover
 * request may be customised by passing in a non-NULL request.
 *
 * The takeover sequence: the old daemon stops accepting new clients, then it
 * waits until all current client connections are closed. When that happens, it
 * serializes its current state and sends that as a reply, which is then
 * returned by this function (therefore, this function won't return until the
 * previous instance has shut down).
 *
 * The daemon, after calling daemon_takeover is expected to set up its
 * daemon_state using the reply from this function and call daemon_start as
 * usual.
 */
daemon_reply daemon_takeover(daemon_info i, daemon_request r);

/* Call this to request a clean shutdown of the daemon. Async safe. */
void daemon_stop(void);

...

客户端句柄

每个客户端连接时都会创建一个新的线程和客户端句柄来处理与之对应的请求。

$ cat libdaemon/server/daemon-server.h
...

typedef struct {
	int socket_fd; /* the fd we use to talk to the client */
	pthread_t thread_id;
	char *read_buf;
	void *private; /* this holds per-client state */
} client_handle;

...

守护服务回调函数

$ cat libdaemon/server/daemon-server.h
...

/*
 * The callback. Called once per request issued, in the respective client's
 * thread. It is presented by a parsed request (in the form of a config tree).
 * The output is a new config tree that is serialised and sent back to the
 * client. The client blocks until the request processing is done and reply is
 * sent.
 */
typedef response (*handle_request)(struct daemon_state s, client_handle h, request r);

...

响应请求

$ cat libdaemon/server/daemon-server.h
...

/*
 * Craft a simple reply, without the need to construct a config_tree. See
 * daemon_send_simple in daemon-client.h for the description of the parameters.
 */
response daemon_reply_simple(const char *id, ...);

static inline int daemon_request_int(request r, const char *path, int def) {
	if (!r.cft)
		return def;
	return dm_config_find_int(r.cft->root, path, def);
}

static inline const char *daemon_request_str(request r, const char *path, const char *def) {
	if (!r.cft)
		return def;
	return dm_config_find_str(r.cft->root, path, def);
}

...

客户端

守护服务句柄与信息

$ cat libdaemon/client/daemon-client.h
...

typedef struct {
	int socket_fd; /* the fd we use to talk to the daemon */
	const char *protocol;
	int protocol_version;  /* version of the protocol the daemon uses */
	int error;
} daemon_handle;

typedef struct {
	const char *path; /* the binary of the daemon */
	const char *socket; /* path to the comms socket */
	unsigned autostart:1; /* start the daemon if not running? */

	/*
	 * If the following are not NULL/0, an attempt to talk to a daemon which
	 * uses a different protocol or version will fail.
	 */
	const char *protocol;
	int protocol_version;
} daemon_info;

...

打开和关闭与守护服务的连接

$ cat libdaemon/client/daemon-client.h
...

/*
 * Open the communication channel to the daemon. If the daemon is not running,
 * it may be autostarted based on the binary path provided in the info (this
 * will only happen if autostart is set to true). If the call fails for any
 * reason, daemon_handle_valid(h) for the response will return false. Otherwise,
 * the connection is good to start serving requests.
 */
daemon_handle daemon_open(daemon_info i);
...

/* Shut down the communication to the daemon. Compulsory. */
void daemon_close(daemon_handle h);

...

构造请求

辅助函数:

$ cat libdaemon/client/config-util.h
...

struct buffer {
	int allocated;
	int used;
	char *mem;
};

int buffer_append_vf(struct buffer *buf, va_list ap);
int buffer_append_f(struct buffer *buf, ...);
int buffer_append(struct buffer *buf, const char *string);
void buffer_init(struct buffer *buf);
void buffer_destroy(struct buffer *buf);
int buffer_realloc(struct buffer *buf, int required);

int buffer_line(const char *line, void *baton);

int set_flag(struct dm_config_tree *cft, struct dm_config_node *parent,
	     const char *field, const char *flag, int want);

void chain_node(struct dm_config_node *cn,
                struct dm_config_node *parent,
                struct dm_config_node *pre_sib);

struct dm_config_node *make_config_node(struct dm_config_tree *cft,
					const char *key,
					struct dm_config_node *parent,
					struct dm_config_node *pre_sib);

int compare_value(struct dm_config_value *a, struct dm_config_value *b);
int compare_config(struct dm_config_node *a, struct dm_config_node *b);

struct dm_config_node *make_text_node(struct dm_config_tree *cft,
				      const char *key,
				      const char *value,
				      struct dm_config_node *parent,
				      struct dm_config_node *pre_sib);

struct dm_config_node *make_int_node(struct dm_config_tree *cft,
				     const char *key,
				     int64_t value,
				     struct dm_config_node *parent,
				     struct dm_config_node *pre_sib);

struct dm_config_node *config_make_nodes_v(struct dm_config_tree *cft,
					   struct dm_config_node *parent,
					   struct dm_config_node *pre_sib,
					   va_list ap);
struct dm_config_node *config_make_nodes(struct dm_config_tree *cft,
					 struct dm_config_node *parent,
					 struct dm_config_node *pre_sib,
					 ...);

...

构建及销毁请求和响应数据:

$ cat libdaemon/client/daemon-client.h
...

daemon_request daemon_request_make(const char *id);
int daemon_request_extend(daemon_request r, ...);
int daemon_request_extend_v(daemon_request r, va_list ap);
void daemon_request_destroy(daemon_request r);

void daemon_reply_destroy(daemon_reply r);

...

发送请求和等待响应

辅助函数:

$ cat libdaemon/client/daemon-io.h
...

int buffer_read(int fd, struct buffer *buffer);
int buffer_write(int fd, const struct buffer *buffer);

...

发送请求并等待响应:

$ cat libdaemon/client/daemon-client.h
...

/*
 * Send a request to the daemon, waiting for the reply. All communication with
 * the daemon is synchronous. The function handles the IO details and parses the
 * response, handling common error conditions. See "daemon_reply" for details.
 *
 * In case the request contains a non-NULL buffer pointer, this buffer is sent
 * *verbatim* to the server. In this case, the cft pointer may be NULL (but will
 * be ignored even if non-NULL). If the buffer is NULL, the cft is required to
 * be a valid pointer, and is used to build up the request.
 */
daemon_reply daemon_send(daemon_handle h, daemon_request r);

/*
 * A simple interface to daemon_send. This function just takes the command id
 * and possibly a list of parameters (of the form "name = %?", "value"). The
 * type (string, integer) of the value is indicated by a character substituted
 * for ? in %?: d for integer, s for string.
 */
daemon_reply daemon_send_simple(daemon_handle h, const char *id, ...);
daemon_reply daemon_send_simple_v(daemon_handle h, const char *id, va_list ap);

...

解析响应

$ cat libdaemon/client/daemon-client.h
...

static inline int64_t daemon_reply_int(daemon_reply r, const char *path, int64_t def)
{
	return dm_config_find_int64(r.cft->root, path, def);
}

static inline const char *daemon_reply_str(daemon_reply r, const char *path, const char *def)
{
	return dm_config_find_str_allow_empty(r.cft->root, path, def);
}

...

© 著作权归作者所有

共有 人打赏支持
LastRitter
粉丝 36
博文 39
码字总数 185010
作品 0
武汉
高级程序员
Raid5两块硬盘离线解决方案 -阵列数据恢复案例

#服务器数据恢复背景描述: 需要进行数据恢复的磁盘阵列是两组分别由4块600G容量的SAS硬盘组成的raid5磁盘阵列,ext3文件系统、lvm结构。 磁盘阵列中1号硬盘离线,热备盘启动同步,在同步过程...

宋国建
04/11
0
0
通用线程: 学习 Linux LVM

通用线程: 学习 Linux LVM “逻辑卷管理”为存储器管理带来的魔力 Daniel Robbins (drobbins@gentoo.org), 总裁兼 CEO, Gentoo Technologies, Inc. 简介: 在本文中,Daniel 向您介绍了 Linu...

Start-up
2012/05/28
0
0
服务器raid5两块硬盘离线vxfs文件系统恢复数据方法

服务器数据恢复故障描述 客户的服务器共有8块450GB SAS硬盘,其中7块硬盘组成一个RAID5阵列,1块热备盘。阵列中2块硬盘损坏并离线,导致RAID5阵列瘫痪,进而影响上层LUN无法正常使用。硬盘无...

宋国建
04/19
0
0
通过拼数据库碎片的方式恢复虚拟机磁盘文件丢失问题

背景概述 由于服务器突然断电,造成我公司Xen Server服务器中一台VPS(即Xen Server虚拟机)不可用,虚拟磁盘文件丢失。硬件环境是Dell 720服务器配戴一张H710P的RAID卡,由4块希捷2T STAT硬...

宋国建
2017/08/16
0
0
【长文+图片】HP FC MSA2000服务器瘫痪数据恢复过程

服务器数据恢复故障描述 某公司的一台HP FC MSA2000服务器,服务器中搭建RAID5阵列,服务器正常使用过程中出现2块硬盘损坏并离线,而此时只有一块热备盘成功激活,因此导致RAID5阵列瘫痪,上...

宋国建
07/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

软件测试工具书籍与面试题汇总下载(持续更新)

简介 本文是https://github.com/china-testing/python-api-tesing/blob/master/books.md 的节选。 欢迎转载,转载请附带此简介,谢谢! 试题 软件测试综合面试题(高级测试)-试题.pdf 软件测试...

python测试开发人工智能安全
22分钟前
0
0
java.sql.SQLException: Io 异常: The Network Adapter could not establish the connection 解决

有个项目使用的log4j进行日志记录的,同时也是用log4j中的数据库配置直接把相应级别的日志直接插入oracle。 在把项目部署的另一个内网环境时候,把项目的其他配置都改了,唯独log4j中的数据库...

哥本哈根的小哥
32分钟前
0
0
耗时 2 年,用 8.5 万块乐高积木最牛复刻 Apple Park

简评:国外大佬复刻 Apple Park,看了一下细节,确实厉害!只有你想不到,没有乐高拼不起来的,有没有乐高大神挑战一下? 苹果公园以各种各样的方式鼓舞人心,让人感兴趣。从建筑、可持续性和...

极光推送
33分钟前
0
0
记一次查找Hdfs磁盘占用空间比实际存储文件大4倍的原因

在一次主备namenode发生切换后,重启datanode节点,发现磁盘空间很大,想清理一下磁盘, 通过命令Hdfs dfs -du -h --max-depth=1 / 发现实际文件的大小只有8g,通过du -h --max-depth=1 /ha...

PageYi
今天
5
0
阿里云推荐引擎使用教程

产品概述: 推荐引擎(Recommendation Engine,以下简称RecEng,特指阿里云推荐引擎)是在阿里云计算环境下建立的一套推荐服务框架,目标是让广大中小互联网企业能够在这套框架上快速的搭建满...

mcy0425
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部