Memcached的工作方式:以下的部分中,读者最好能准备一份memcached的源代码.
Memcached是传统的网络服务程序,如果启动的时候使用了-d参数,它会以守护进程的方式执行,创建守护进程由daemon.c完成,这个程序只有一个daemon函数,这个函数很简单,如无特殊说明,代码以1.2.1为准,代码如下:
- #include <fcntl.h>
- #include <stdlib.h>
- #include <unistd.h>
-
- int
- daemon(nochdir, noclose)
- int nochdir, noclose;
- {
- int fd;
-
- switch (fork()) {
- case -1:
- return (-1);
- case 0:
- break;
- default:
- _exit(0);
- }
-
- if (setsid() == -1)
- return (-1);
-
- if (!nochdir)
- (void)chdir(”/”);
-
- if (!noclose && (fd = open(”/dev/null”, O_RDWR, 0)) != -1) {
- (void)dup2(fd, STDIN_FILENO);
- (void)dup2(fd, STDOUT_FILENO);
- (void)dup2(fd, STDERR_FILENO);
- if (fd > STDERR_FILENO)
- (void)close(fd);
- }
- return (0);
- }
这个函数 fork 了整个进程之后,父进程就退出,接着重新定位 STDIN 、 STDOUT 、 STDERR 到空设备,daemon 就建立成功了,代码如下:
- <?php
- class Memcached
- {
- private $mem;
- public $pflag='';
- private function memConnect($serkey){
- require 'config.php';
- $server = $memcached;
- $this->mem = new Memcache;
- $link = !$this->pflag ? 'connect' : 'pconnect' ;
- $this->mem->$link($server[$serkey][0],$server[$serkey][1]) or $this->errordie('memcached connect error');
- }
- public function set($ser_key,$values,$flag='',$expire=''){
- $this->memConnect($this->tag($ser_key));
- if($this->mem->set($ser_key,$values,$flag,$expire)) return true;
- else return false;
- }
- public function get($ser_key){
- $this->memConnect($this->tag($ser_key));
- if($var=$this->mem->get($ser_key)) return $var;
- else return false;
- }
- private function tag($ser_key){
- $tag=explode('_',$ser_key);
- return $tag[0];
- }
- private function errordie($errmsg){
- die($errmsg);
- }
- }
- ?>
-
- class Mysql
- {
- private $mysqlmaster;
- private $myssqlslave;
- private static $auid=0;
- public function __construct(){
- require 'config.php';
- $msg = $mysql;
-
- $this->mysqlmaster = new mysqli($msg['master'][0],$msg['master'][1],$msg['master'][2],$msg['master'][3]);
- $this->mysqlslave = $this->autotranscat($msg);
- if(mysqli_connect_errno()){
- printf("Connect failed: %s ",mysqli_connect_error());
- exit();
- }
- if(!$this->mysqlmaster->set_charset("latin1") && !$this->mysqlslave->set_charset("latin1")){
- exit("set charset error");
- }
- }
- private function autotranscat($mysql){
- session_start();
- $_SESSION['SID']!=0 || $_SESSION['SID']=0 ;
- if($_SESSION['SID'] >=count($mysql)-1) $_SESSION['SID'] = 1;
- else $_SESSION['SID']++;
- $key = 'slave_'.$_SESSION['SID'];
- echo($_SESSION['SID']);
- return new mysqli($mysql[$key][0],$mysql[$key][1],$mysql[$key][2],$mysql[$key][3]);
- }
- public function mquery($sql){
- if(!$this->mysqlmaster->query($sql)){
- return false;
- }
- }
- public function squery($sql){
- if($result=$this->mysqlslave->query($sql)){
- return $result;
- }else{
- return false;
- };
- }
- public function fetArray($sql){
- if($result=$this->squery($sql)){
- while($row=$result->fetch_array(MYSQLI_ASSOC)){
- $resultraa[] = $row;
- };
- return $resultraa;
- }
- }
- }
- ?>
- require 'init.php';
- $mem = new Memcached;
-
-
-
-
-
- $sq = new Mysql;
- $sql = "insert into mybb(pid) values(200)";
- $mdsql = md5($sql);
- if(!$result=$mem->get('cn_'.$mdsql)){
- $sq->mquery("insert into mybb(pid) values(200)");
- $result = $sq->fetArray("select * from mybb");
- foreach($result as $var){
- echo $var['pid'];
- }
- $mem->set('cn_'.$mdsql,$result);
- }else{
- foreach($result as $var){
- echo $var['pid'];
- }
- }
- ?>
-
- <?php
- $memcached = array(
- 'cn'=>array('192.168.254.144',11211),
- 'en'=>array('192.168.254.144',11212)
- );
- $mysql = array(
- 'master'=>array('192.168.254.213','root','1','mydz'),
- 'slave_1'=>array('192.168.254.144','root','1','mydz')
- );
- ?>
Memcached 本身的启动过程,在 memcached.c 的 main 函数中顺序如下:
1 、调用 settings_init() 设定初始化参数
2 、从启动命令中读取参数来设置 setting 值
3 、设定 LIMIT 参数
4 、开始网络 socket 监听(如果非 socketpath 存在)( 1.2 之后支持 UDP 方式)
5 、检查用户身份( Memcached 不允许 root 身份启动)
6 、如果有 socketpath 存在,开启 UNIX 本地连接(Sock 管道)
7 、如果以 -d 方式启动,创建守护进程(如上调用 daemon 函数)
8 、初始化 item 、 event 、状态信息、 hash 、连接、 slab
9 、如设置中 managed 生效,创建 bucket 数组
10 、检查是否需要锁定内存页
11 、初始化信号、连接、删除队列
12 、如果 daemon 方式,处理进程 ID
13 、event 开始,启动过程结束,main 函数进入循环.
在 daemon 方式中,因为 stderr 已经被定向到黑洞,所以不会反馈执行中的可见错误信息.
memcached.c 的主循环函数是 drive_machine,传入参数是指向当前的连接的结构指针,根据 state 成员的状态来决定动作. |