背景

  对于单机数据库而言[如postgres],死锁检测机制相对于分布式数据库如greenplum来说相对简单,其本质是通过相关约束构造等待图,如果出现死锁情况,则采用拓扑排序重排序列规避死锁,若无解法则回滚等待环中的某一事务/或若干事务来打破死锁。但是对于share nothing 的MPP架构数据库而言,采用上述方法无法获取全局等待视图,死锁的攻克显得力不从心.另辟蹊径,greenplum设计的方法是:通过在 master 节点设置全局死锁检测进程,不断地轮询计算节点上的本地等待图graph,在master上汇总形成全局等待图,利用相应的规则和算法来打破死锁。接下来一起学习,探索源码:

关键数据结构

1 数据结构流转图

greenplum开启远程服务 greenplum原理_greenplum开启远程服务


2 概念介绍

greenplum开启远程服务 greenplum原理_数据结构_02

3 数据结构分析
3.1 GddCtx:全局死锁上下文结构体,该结构体记录了全局等待图的相关信息,包括所有节点[分布式事务]的出/入度、segid与节点间映射关系、segid与本地等待图间的映射关系信息

struct GddCtx
{
	GddStat		topstat;		/* overall in/out degrees of all verts on all graphs */
	GddMap		globals;		/* Map<vid, Stat>, global in/out degrees */
	GddMap		graphs;			/* Map<segid, Graph>, the local graphs */
};

3.2 GddStat:记录某个分布式事务节点的出入度信息

/*
 * Accounting information of a vert.
 */
struct GddStat
{
	int			id;				/* vert id */        // 节点号  ===》 分布式事务号
	int			indeg;			/* in degree */		 // 该节点的入度
	int			outdeg;			/* out degree */     // 该节点的出度
};

3.3 GddEdge:该结构记录等待图中边信息:包括是否为硬边、出节点、入节点信息和存放的数据

/*
 * A directed edge.
 */
struct GddEdge
{
	bool		solid;			/* a solid edge? */
	GddVert		*from;			/* the from vert */
	GddVert		*to;			/* the to vert */
	void        *data;
};

3.4 GddVert:该结构为计算segment上某个节点的相关信息,包括该节点在全局视图中的出入度,出边和入边等信息

/*
 * A vertex (vert) on a segment.
 */
struct GddVert
{
	int			id;				/* vert id */

	/*
	 * Pointer to ctx->topstat, all the verts on all the globals maintain
	 * the overall in/out degrees count together.
	 */
	GddStat		*topstat;

	/*
	 * Pointer to the `global` struct with the same vert id, the global
	 * in/out degrees of vert.
	 */
	GddStat		*global;

	List		*edgesIn;		/* List<Edge>, directed edges to vert */
	List		*edgesOut;		/* List<Edge>, directed edges from vert */

	/*
	 * The data set and used only by the caller, GDD does not touch or access
	 * it.
	 */
	void		*data;
};

3.5 GddMap:本质GddPair数组,保存的是K-V映射关系

/*
 * A <int, pointer> pair.
 */
struct GddPair
{
	int			key;
	void		*ptr;
};

/*
 * A simple int->ptr map, implemented with array.
 */
struct GddMap
{
	int			length;			/* length of the <k,v> array */
	int			capacity;		/* capacity of the <k,v> array */

	GddPair		*pairs;			/* array of <k,v> pairs */
};

3 GDD进程介绍和工作总流程

该进程是greenplum内置的辅助进程,postmaster正式接受客户端请求前在后台启动

{"global deadlock detector process", "global deadlock detector process",
	 BGWORKER_SHMEM_ACCESS | BGWORKER_BACKEND_DATABASE_CONNECTION,
	 BgWorkerStart_RecoveryFinished,
	 0, /* restart immediately if gdd exits with non-zero code */
	 "postgres", "GlobalDeadLockDetectorMain", 0, {0}, 0,
	 GlobalDeadLockDetectorStartRule},        
	 
	 运行规则:
	
 bool GlobalDeadLockDetectorStartRule(Datum main_arg)
{
	if (Gp_role == GP_ROLE_DISPATCH &&
		gp_enable_global_deadlock_detector)
		return true;

	return false;
}

入口函数:GlobalDeadLockDetectorMain

/*
 * GlobalDeadLockDetectorMain
 */
void
GlobalDeadLockDetectorMain(Datum main_arg)
{
	am_global_deadlock_detector = true;                           // 更新标识

	pqsignal(SIGHUP, sigHupHandler); 							  // 注册信号处理函数

	/* We're now ready to receive signals */
	BackgroundWorkerUnblockSignals();							// 打开信号

	/* Connect to our database */
	BackgroundWorkerInitializeConnection(DB_FOR_COMMON_ACCESS, NULL, 0);        // 连接数据库

	/* disable orca here */
	extern bool optimizer;
	optimizer = false;

	GlobalDeadLockDetectorLoop();                            // 死锁检测,轮询,下节重点讲解

	/* One iteration done, go away */
	proc_exit(0);
}