文档章节

LVM源码分析2-libdaemon

LastRitter
 LastRitter
发布于 2017/09/08 23:21
字数 1390
阅读 42
收藏 0
点赞 0
评论 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
粉丝 34
博文 36
码字总数 168045
作品 0
武汉
高级程序员
Raid5两块硬盘离线解决方案 -阵列数据恢复案例

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

宋国建 ⋅ 04/11 ⋅ 0

通用线程: 学习 Linux LVM

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

Start-up ⋅ 2012/05/28 ⋅ 0

服务器raid5两块硬盘离线vxfs文件系统恢复数据方法

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

宋国建 ⋅ 04/19 ⋅ 0

通过拼数据库碎片的方式恢复虚拟机磁盘文件丢失问题

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

宋国建 ⋅ 2017/08/16 ⋅ 0

HP存储raid5两块硬盘离线lvm下vxfs文件系统恢复数据过程

故障描述 HP FC MSA2000存储,由于RAID5阵列中出现2块硬盘损坏并离线,而此时只有一块热备盘成功激活,因此导致RAID5阵列瘫痪,上层LUN无法正常使用,用户联系联系北亚数据,整个存储空间由8...

张宇 ⋅ 2017/01/13 ⋅ 0

Xen server虚拟化中虚拟机磁盘文件丢失的处理办法

描述 因服务器突然断电原因导致Xen Server服务器中一台VPS(即Xen Server虚拟机)不可用,虚拟磁盘文件丢失,通过电话联系北亚数据来进行恢复。硬件环境是Dell 720服务器配戴一张H710P的RAI...

张宇 ⋅ 2017/02/13 ⋅ 0

Xen Server虚拟机数据丢失的恢复过程

虚拟机数据丢失情况描述 因服务器突然断电原因导致Xen Server服务器中一台VPS(即Xen Server虚拟机)不可用,虚拟磁盘文件丢失。硬件环境是Dell 720服务器配戴一张H710P的RAID卡,由4块希捷2...

宋国建 ⋅ 06/06 ⋅ 0

Xen server虚拟化磁盘文件丢失恢复案例实施过程

虚拟机环境描述 虚拟机硬件环境为一台某品牌720型号服务器,4块2T STAT硬盘配戴一张H710P的RAID卡组成raid10磁盘阵列。操作系统为Xen Server 6.2版本,Windows Server 2003系统。上层是Web服...

宋国建 ⋅ 04/27 ⋅ 0

linux磁盘管理之LVM

一、需求分析 1,当我们需要存储一个500G的不可分割文件时,但是我们设备上没有这么大的单个磁盘。 2,当我们在搭建一个服务,由于日常运转产生大量文件,磁盘容量不够用了,怎么办?添加磁盘...

Becaning ⋅ 2014/03/05 ⋅ 0

AIX小机lvm信息丢失数据恢复方案

方案适用故障情况 DS4800存储服务器lvm信息丢失。 基于DS4800服务器的aix小机卷丢失。 服务器数据恢复方案 1、服务器硬盘镜像 为防止数据恢复过程中由于误操作对原始磁盘造成二次破坏,所有数...

宋国建 ⋅ 04/28 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

SAS笔记-宏2

宏是一种文本,一般来说其编译是在程序执行之前。 宏变量的创建 %let语句 %let macro_variables = text; %let是常见的宏变量建立方式,其编译就在执行前。如下例中,想要宏变量test等于数据集...

tonorth123 ⋅ 8分钟前 ⋅ 0

如何使用serverchan微信推送告警

之前实现推送告警信息到微信的方法有如下几种: 1、通过企业公众号实现----收费: 2、通过QQ邮箱,在微信平台上开启收到邮件进行提醒; 3、第三方告警平台API,一般也是收费的; 不过最近看文...

问题终结者 ⋅ 35分钟前 ⋅ 0

TCP的RPC

RPC就是远程方法调用(Remote Process Call ),包含了客户端和服务端,涉及了对象的序列化传输。 1.服务端启动,注册远程调用的类2.客户端发送请求信息包含类、方法、参数的一些信息、序列化传...

Cobbage ⋅ 56分钟前 ⋅ 0

IOS-UI UI初步代码布局添加事件

ISO开发界面,UI是必须学习的一部分,其实很早之前想学来了,一直没有沉下心来学习。看到IOS的代码风格和布局就别扭的不行,跟java代码和android布局比较显得不是那么方便,所以一直到现在。...

京一 ⋅ 今天 ⋅ 0

浅谈OpenDaylight的二次开发

OpenDaylight作为一款开源SDN网络控制器,依托于强大的社区支持以及功能特性,成为了目前主流的SDN网络控制器开发平台。在比较稳定的OpenDaylight Helium版本中,已经为开发者提供了大量的网...

wangxuwei ⋅ 今天 ⋅ 0

API 开发中可选择传递 token 接口遇到的一个坑

在做 API 开发时,不可避免会涉及到登录验证,我使用的是jwt-auth 在登录中会经常遇到一个token过期的问题,在config/jwt.php默认设置中,这个过期时间是一个小时,不过为了安全也可以设置更...

等月人 ⋅ 今天 ⋅ 0

Java NIO之文件处理

程序要操作本地操作系统的一个文件,可以分为以下三个部分: 对文件位置的操作 对文件的操作 对文件内容的操作 其中,对文件内容的操作在 Java NIO之Channel 中已经有了介绍,通过FileChann...

士别三日 ⋅ 今天 ⋅ 0

Maven的pom.xml配置文件详解

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.......

小海bug ⋅ 今天 ⋅ 0

解决httpclient超时设置不生效的问题

最近公司有项目需要通过http调用第三方服务,且第三方服务偶有超时,故需要设置一定的超时时间防止不响应的情况出现。 初始设置如下: [java] view plain copy //超时设置 RequestConfig re...

Mr_Tea伯奕 ⋅ 今天 ⋅ 0

过滤器Filter和拦截器HandlerInterceptor

过滤器 依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要...

hutaishi ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部