Yangming's Blog

beware the barrenness of a busy life

Pgbouncer源码——ObjectManager

12 Jun 2018 » PostgreSQL, Pgbouncer
  • TOC

本模块实现在不同的list之间,操作pgbouncer的objects

Objects

AAtree

/**
 * Tree header, for storing helper functions.
 */
struct AATree {
	struct AANode *root;
	int count;
	aatree_cmp_f node_cmp;
	aatree_walker_f release_cb;
};
/**
 * Tree node.  Embeddable, parent structure should be taken
 * with container_of().
 *
 * Techinally, the full level is not needed and 2-lowest
 * bits of either ->left or ->right would be enough
 * to keep track of structure.  Currently this is not
 * done to keep code simple.
 */
struct AANode {
	struct AANode *left;	/**<  smaller values */
	struct AANode *right;	/**<  larger values */
	int level;		/**<  number of black nodes to leaf */
};

extern struct AATree user_tree;

AAtree是红黑树的变种,通过添加了约束(红节点只能是右节点),减少了树的可能形状;

StatList

/**
 * Header structure for StatList.
 */
struct StatList {
	/** Actual list head */
	struct List head;
	/** Count of objects currently in list */
	int cur_count;
#ifdef LIST_DEBUG
	/** List name */
	const char *name;
#endif
};

/** Define and initialize StatList head */
#ifdef LIST_DEBUG
#define STATLIST(var) struct StatList var = { {&var.head, &var.head}, 0, #var }
#else
#define STATLIST(var) struct StatList var = { {&var.head, &var.head}, 0 }
#endif

extern struct StatList user_list;
extern struct StatList pool_list;
extern struct StatList database_list;
extern struct StatList autodatabase_idle_list;
extern struct StatList login_client_list;

带统计信息的双向链表,不同对象的容器;

Slab

extern struct Slab *client_cache;
extern struct Slab *server_cache;
extern struct Slab *db_cache;
extern struct Slab *pool_cache;
extern struct Slab *user_cache;
extern struct Slab *iobuf_cache;

预先初始化的对象集合,在后期需要的时候直接从相应cache中获取对象,比如:;

	server = slab_alloc(server_cache);
	if (!server)
		return false;

Functions

Pgbouncer使用<db,user>组合可以唯一确定一个pool;每个pguser对应一个pool集合 $poolForUser_n$;每个pgdatabase对应一个pool 集合$poolForDatabase_m$;$poolForuser_n ∩ poolForDatabase_m$ 这个交集,就是某一个<db,user> 对应的pool;

objects模块,提供了若干函数,对pgbouncer的objects进行增删改查

  • 加某些对象

    • PgDatabase * add_database(const char *name) _MUSTCHECK;

      upsert 一个新的pgDatabase对象,放到相应容器中,并返回

    • PgDatabase *register_auto_database(const char *name);

      pgbouncer的配置文件中,可以用key=value的形式直接配置一个db,这种方式是autodb,如果相应的server一直idle,在autodb_idle_timeout之后就会被清理;

    • PgUser * add_user(const char *name, const char *passwd) _MUSTCHECK;

      往user_cache中,添加user

    • PgUser * add_db_user(PgDatabase *db, const char *name, const char *passwd) _MUSTCHECK;

      往db->user_tree中,添加user,在db中查询过的user

    • PgUser * force_user(PgDatabase *db, const char *username, const char *passwd) _MUSTCHECK;

      关于forced_user的意义,如果pgbouncer的database中,使用连接串的方式并且连接串中指定了user,那么pgbouncer和PostgreSQL之间的连接强制使用这个user,不管前段的用户是什么;

    • PgUser * add_pam_user(const char *name, const char *passwd) _MUSTCHECK;

      pam认证方式

  • 除某些对象

    • evict_connectionevict_user_connection

      清理poolForDatabase_m和poolForUser_n中的连接

    • disconnect_serverdisconnect_client

      释放连接

    • objects_cleanup

      只是在main最后的cleanup中调用了,在生产环境中几乎没用

  • 动某些对象信息

    • PgSocket *accept_client(int sock, bool is_unix) _MUSTCHECK;

      接受client连接

    • bool release_server(PgSocket *server)void activate_client(PgSocket *client);

      释放server的连接,连接的状态从connecting/active -> idle, 可能的话会和client端解除连接 ,此时会及时的调用activate_client 唤醒一个client;

    • void forward_cancel_request(PgSocket *server);

      server cancel 这次请求

    • void accept_cancel_request(PgSocket *req);

      client 接收到了 cancel的response,并处理

    • use_client_socketuse_server_socket

      takeover的时候,复用Socket

    • change_client_statechange_server_state

      改变状态,意味着改变相应的list,这两个函数就是管理状态和list的对应

    • void tag_database_dirty(PgDatabase *db);

      db上的查询发生改变,

    • void tag_autodb_dirty(void);

      autodb 的链接串发生改变

    • void tag_host_addr_dirty(const char *host, const struct sockaddr *sa);

      链接上的请求结果发生改变

    • void reuse_just_freed_objects(void);

    object从just_freed到freedlist中

    • init_objectsinit_caches

      加载配置之前,初始化对象

  • 找某些对象的信息

    • find_database find_user

      从相应list中,找到odject

    • PgPool *get_pool(PgDatabase *, PgUser *);

      按照db-user对,唯一标识一个pool;

    • PgSocket *compare_connections_by_time(PgSocket *lhs, PgSocket *rhs);

      返回rhs lhs中,请求时间老的连接

    • bool find_server(PgSocket *client) _MUSTCHECK;

      client请求server连接,如果找到了,那么两个socket建立连接关系,否则,放在等待队列里

    • bool finish_client_login(PgSocket *client) _MUSTCHECK;

      改变client的状态,模拟server发送一些欢迎语

    • bool check_fast_fail(PgSocket *client) _MUSTCHECK;

    • void launch_new_connection(PgPool *pool);

      新的client连接请求,快速检查client对应的pool中有没有可用的server连接,没有的话,不放在等待队列中,只是触发一次新的launch_new_connection,pool申请新的连接

    • int get_active_client_count(void);int get_active_server_count(void);

      字面意思,都是从slab这个带统计信息的双向链表中取count

  • 其他

    // for_each
    void for_each_server(PgPool *pool, void (*func)(PgSocket *sk));