文档章节

LVM源码分析2-libdaemon

LastRitter
 LastRitter
发布于 2017/09/08 23:21
字数 1390
阅读 48
收藏 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
粉丝 35
博文 36
码字总数 168045
作品 0
武汉
高级程序员
通用线程: 学习 Linux LVM

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

Start-up
2012/05/28
0
0
Raid5两块硬盘离线解决方案 -阵列数据恢复案例

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

宋国建
04/11
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

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Confluence 6 反向跟踪

当反向跟踪(Trackback )被启用后,在任何你链接到可用启用自动发现功能的外部页面中,Confluence 将会自动发送一个方向跟踪 ping,这个 ping 能通知链接的页面有了内容改变。 Confluence 页...

honeymose
9分钟前
0
0
日期和时间API - 读《Java 8实战》

日期与时间 LocalDate 创建一个LocalDate对象并读取其值 // 根据年月日创建日期LocalDate date1 = LocalDate.of(2014, 3, 18);// 读取System.out.println(date1.getYear()); // 2014Sys...

yysue
17分钟前
0
0
8月15日任务

8月15日任务 Memcached命令行 • telnet 127.0.0.1 11211 • set key2 0 30 2 ab STORED get key2 VALUE key2 0 2 ab END 实例: [root@localhost 02]# telnet 127.0.0.1 11211-bash: te......

寰宇01
29分钟前
1
0
LNMP架构(Nginx访问日志、Nginx日志切割、静态文件不记录日志和过期时间)

Nginx访问日志 1.打开配置文件,搜索log_format vim /usr/local/nginx/conf/nginx.conf 2.访问日志常用变量含义 $remote_addr : 客户端IP(公网IP) $http_x_forwarded_for : 代理服务器的IP ...

蛋黄_Yolks
29分钟前
0
0
lombok 不用再写pojo的getset

java实体类不写get/set方法 1、下载地址https://projectlombok.org/download Myeclipse、eclipse安装lombok Lombok是一种Java实用工具,可以帮助开发人员消除Java的冗长,具体看lombok的官网...

木之下
37分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部