nodejs对memcache进行备份与恢复

野生程序猿-杂烧4年前随意分享3041

memcache是个古老的高速缓存工具,前辈们古老的程序还用着。但是市场上没有完美的备份恢复工具,老板让我开发一个。

这需求让我两眼一抹黑,完全不知所措。先模拟一下思路,可以telenet到端口上,然后命令提取。这里坑很多,首先memcache只能返回2MB的数据,需要修改源码再进行编译,改成分页效果。这个我不在行,与运维同事配合修改了源码并编译成功了(过程还是挺曲折的)。

接着就是代码。nodejs编写,多线程。

JavaScript
#! /usr/bin/env node

//需要 npm install memcached -g    /    npm install memcached  2个命令(涉及环境变量问题,尽量这2个都用一下)

var $type='stat';
var $str="";
var $bak_file="";
var $num="";	//预留,暂时不用
var $argv=process.argv.splice(2);
//console.log($argv);
var $mem_ip="";
var $mem_port="";


// 对Date的扩展,将 Date 转化为指定格式的String
// 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符,
// 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
// 例子:
// (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
// (new Date()).Format("yyyy-M-d h:m:s.S")      ==> 2006-7-2 8:9:4.18
Date.prototype.Format = function (fmt) { //author: meizz
    var o = {
        "M+": this.getMonth() + 1, //月份
        "d+": this.getDate(), //日
        "h+": this.getHours(), //小时
        "m+": this.getMinutes(), //分
        "s+": this.getSeconds(), //秒
        "q+": Math.floor((this.getMonth() + 3) / 3), //季度
        "S": this.getMilliseconds() //毫秒
    };
    if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
    for (var k in o)
        if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
    return fmt;
}
//调用:
//var time1 = new Date().Format("yyyy-MM-dd");
//var time2 = new Date().Format("yyyy-MM-dd HH:mm:ss");



var time=function()
{
	var result=Date.parse(new Date());
	result=Math.ceil(result/1000);
	return result;
}


function chr(code)
{
	return String.fromCharCode(code);
}

function strpos(allstr,findstr)
{
	return allstr.indexOf(findstr);
}

function readtxt(url)
{
    try{
        var fs = require('fs');
        var result=fs.readFileSync(url, 'utf8');
    }catch(e){
        var result='';
    }


    return result;
}

function savetxt(url,content,back)
{
    if(!back)
    {
        var back=function(result){
            console.log(result);
        }
    }
    var fs = require('fs');
    fs.writeFile(url, content,function(err){
        back(err);
    });
}

function appendtxt(url,content)
{
    //console.log(content);

    var fs = require('fs');
    //console.log(__dirname+'/'+url);
    fs.appendFileSync(__dirname+'/'+url, content);
}

function str_number(str,num)
{
	if(str.length>=num)
	{
		return str;
	}
	var result='';
	for(let i=1;i<=num-str.length;i++)
	{
        result=result+' ';
	}
    result=result+str;
	return result;
}

function addlog(content)
{
    //console.log('写日志');
    var fs = require('fs');
    var now_time = new Date().Format("yyyy-MM-dd hh:mm:ss");
    var logurl = 'log/'+new Date().Format("yyyy-MM-dd")+".txt";
    var content="["+now_time+"]	"+content+'\n';

    fs.exists(logurl,function(exists){
        if(exists){
            //console.log("文件存在")
            appendtxt(logurl,content);
        }
        if(!exists){
            fs.createWriteStream(logurl)
            //console.log("文件不存在");

            setTimeout(function()
            {
                appendtxt(logurl,content);
            },100);

        }
    })

}







var go_help=function(){
	console.log(`操作方法
	    [状态] node mem.js 127.0.0.1:11555
	    [备份] node mem.js 127.0.0.1:11555 dump bak_01.txt
	    [恢复] node mem.js 127.0.0.1:11555 set bak_01.txt
	    
	`);
    process.exit();
};

//savetxt("mem_keys.txt",'ssssssssssssss');



try{

	//兼容几种参数错位
	if(strpos($argv[0],":")>0)
	{

        $str=$argv[0];
        $type=$argv[1];
        $bak_file=$argv[2];

	}else if(strpos($argv[1],":")>0){

        $str=$argv[1];
        $type=$argv[2];
        $bak_file=$argv[3];


	}else if(strpos($argv[2],":")>0){

        $str=$argv[2];
        $type=$argv[3];
        $bak_file=$argv[4];


	}

    if(!$type) $type='stat';

	var $str_arr=$str.split(":");
	$mem_ip=$str_arr[0];
	$mem_port=$str_arr[1];
    //console.log($mem_ip);
    //console.log($mem_port);


	if(!$mem_ip || !$mem_port )
	{
		console.error("参数异常");

        go_help();
	}

	if($type=='bak' && !$bak_file)
    {
        $bak_file=new Date().Format("yyyyMMdd_hhmmss")+"_"+$mem_ip+".bak";
    }

    if(($type=='dump' || $type=='bak' || $type=='set' ) && !$bak_file )
    {
        console.error("参数异常");

        go_help();
    }


}catch(e){
	console.error("参数异常");
    process.exit();
}


//process.exit();


var tmp={
	client:null				//client 外置
	,memcached:null
	
}



var cache={
	
	tag:''			//标记当前在做那件事情	get_keys_obj , get_keys  ,
	,send:'' 		//当前send消息缓存的值
	
	,send_now:0	//开始send的标记, 循环开始时把数据写进这个值
	,send_end:0	//结束send的标记, 循环开始时把数据写进这个值
	,keys_obj:{}
	,keys_obj_list:[]//keys_obj 的list形式,有了排序概念

	,keys:[]
	,active_time:time()
	,data:''		//存收到的包的数据
	,output:[]
	//,stats:[]
	,stats_slabs_data:''	//对应send的内容
	,stats_items_data:''
	,key_exptime:{}     //key的过期时间
    ,keys_setvalue_list:[]     //
    ,keys_setvalue_num:{}       //set 指令尝试次数,计次
    ,keys_setvalue_maxnum:3     //set 的最大次数
	,key_num:{}				//得到每个key 列的条数
	,key_back_num:{}				//得到每个key 列的条数 (返回计次)
};

if($type=='set')
{
	const Memcached = require('memcached');
	tmp.memcached = new Memcached($mem_ip+':'+$mem_port);

}


function go_nodememcache(obj,callback,num)
{
	if(!num)
	{
		var num=5;
	}
	num=num-1;
	tmp.memcached.set(obj.key, obj.value, obj.time, function (err)
	{
		if(!err && err!==false)
		{
			callback(true,obj);
		}else{
			if(num>0)
			{
				go_nodememcache(obj,callback,num);
			}else{
				callback(false,obj);
			}
			
		}

	  
	});
}

//百分比处理数据
var tag_dump_pers=function(arr)
{
    if(arr.length<20)
    {
        var this_max_num=arr.length;
    }else{
        var this_max_num=20;
    }
	let per_number=Math.ceil(arr.length/this_max_num);
	var per_obj={};
	for(let i=0;i<this_max_num;i++ )
	{
		let this_number=i*per_number+1;
		let this_per=Math.ceil((i*100*100)/this_max_num)/100;
        per_obj[this_number]=this_per+'%';
	}
	cache.per_obj=per_obj;
	//console.log(per_obj);
}

var goerr=function(msg,console_cache){
    if(!console_cache)
    {
        let console_cache=false;
    }
	if(!msg)
	{
		let msg='程序执行异常,即将退出';
	}

	console.error(msg);
	if(console_cache==true)
	{
        console.log(cache);
	}

	tmp.client.end();
	setTimeout(function(){
        process.exit();
    },500);

}

var action={
    get_stats_send:function()
    {
        //console.log('get_stats_send');
        cache.tag='get_stats';
        cache.send='stats items\n'
        cache.data='';
        tmp.client.write(cache.send);
    }
	//	STAT items:4:number 7623
    ,get_stats_back:function(data)
    {
        //console.log('get_stats_back');
        //console.log(data);
        let data_line=data.split("\n");
        let end_str=data_line[data_line.length-1].trim();
        //console.log(end_str);
        if(end_str=='END')
        {
            //
			cache.stats_items_data=data;
            this.get_stats_slabs_send();
        }else if(end_str=='ERROR'){
            //连接繁忙式异常 重新连接
            this.get_stats_send();
        }else{
            console.error(cache.tag+' 未知异常');
        }

    }
    ,get_stats_slabs_send:function()
    {
    	//stats_items _data	stats_slabs _data
        cache.tag='get_stats_slabs';
        cache.send='stats slabs\n'
        cache.data='';
        tmp.client.write(cache.send);
    }
    ,get_stats_slabs_back:function(data)
    {
        //console.log('get_stats_slabs_back');
        //console.log(data);
        /*
			  #  Item_Size  Max_age   Pages   Count   Full?  Evicted Evict_Time OOM
			  1      80B    280025s       3   38747      no        0        0    0
			  2     104B    268966s       5   40731      no        0        0    0
			  3     136B    269010s       5   36764      no        0        0    0
			  4     176B     18793s       5   27137      no        0        0    0
			  5     224B    280034s       9   40429      no        0        0    0
			  6     280B    280037s       1     563      no        0        0    0
         */

        let data_line=data.split("\n");
        let end_str=data_line[data_line.length-1].trim();
        //console.log(end_str);
        if(end_str=='END')
        {
            //
            cache.stats_slabs_data=data;
            this.get_stats_output();
            //返回数据
        }else if(end_str=='ERROR'){
            //连接繁忙式异常 重新连接
            this.get_stats_slabs_send();
        }else{
            console.error(cache.tag+' 未知异常');
        }

    }

    ,get_stats_output:function()
	{
    	//输出状态的结果
        let stats_items_data=cache.stats_items_data;
        let stats_slabs_data=cache.stats_slabs_data;
        stats_items_data=stats_items_data.replace(/items:/g,'');
        let all_stat_data=stats_items_data.trim()+'\n'+stats_slabs_data.trim();
        let list=all_stat_data.split("\n");
        var key_arr={};
        var stat_obj={};
        for(let i in list)
        {
            let this_str=list[i].trim();
            //var this_reg = new RegExp("^STAT items:(\d*):number (\d*)");
            let this_arr=this_str.match(/STAT ([0-9]{1,5}):([a-zA-Z0-9_]{1,15}) ([0-9]{1,15})/);
            //console.log(this_str);
            //console.log(this_arr);
			try{
                if(this_arr.length>3)
                {
                    let this_num=this_arr[1];
                    let this_key=this_arr[2];
                    let this_value=this_arr[3];
					if(this_key=='free_chunks_end')
					{
                        if(this_value==0)
						{
							this_value='no';
						}else{
                            this_value='yes';
						}
					}

                    if(this_key=='free_chunks_end')
                    {
                        if(this_value==0)
                        {
                            this_value='yes';
                        }else{
                            this_value='no';
                        }
                    }
                    try{
                        if(!key_arr[this_num])
                        {
                            var this_need=1;
                        }else{
                            var this_need=0;
                        }
                    }catch(e){
                        var this_need=1;
                    }
                    if(this_need==1)
                    {
                        key_arr[this_num]=1;
                        stat_obj[this_num]={};
                    }
                    stat_obj[this_num][this_key]=this_value;
                }
			}catch(e){}


        }
        //console.log(stat_obj);
        //Item_Size  Max_age   Pages   Count   Full?  Evicted Evict_Time OOM
		/*
		    number: '563',
    age: '333936',
    evicted: '0',
    evicted_nonzero: '0',
    evicted_time: '0',
    outofmemory: '0',
    tailrepairs: '0',
    reclaimed: '0',
    chunk_size: '280',
    chunks_per_page: '3744',
    total_pages: '1',
    total_chunks: '3744',
    used_chunks: '563',
    free_chunks: '0',
    free_chunks_end: '3181',
    mem_requested: '127073',
    get_hits: '563',
    cmd_set: '563',
    delete_hits: '0',
    incr_hits: '0',
    decr_hits: '0',
    cas_hits: '0',
		 */
        var display_obj={
            chunk_size:'Item_Size'
            ,age:'Max_age'
            ,total_pages:'Pages'
            ,number:'Count'
            ,free_chunks_end:'Full'
            ,evicted:'Evicted'
            ,evicted_time:'Evict_Time'
            ,outofmemory:'OOM'
		};

        var this_out_put=str_number('#',5);
        for(let i in display_obj)
		{
            this_out_put=this_out_put+''+str_number(display_obj[i],15);
		}

		for(let i in stat_obj)
		{
			let this_one_arr=[];
			for(let j in display_obj)
			{
				try{
                    var this_tmp_html=stat_obj[i][j];
				}catch(e){
					var this_tmp_html='';
				}
                this_one_arr.push(str_number(this_tmp_html,15));
			}
            this_out_put=this_out_put+'\n'+str_number(i,5)+''+this_one_arr.join('');
		}
		//正常输出
		console.log(this_out_put);
        savetxt('stat.txt',this_out_put,function(){
            goerr(' 调试end');
		});

        //goerr(' 调试end');
	}

	//001
	,get_keys_obj_send:function()
	{
	    console.log("即将遍历所有key");
		cache.tag='get_keys_obj';
		cache.send='stats items\n'
		cache.data='';
		tmp.client.write(cache.send);
	}
	
	//第一步取到数据(4 做取keys准备)	STAT items:4:number 7623
	,get_keys_obj_back:function(data)
	{
		//console.log('get_keys_obj_back');
		//console.log(data);
		
		let data_line=data.split("\n");
		let end_str=data_line[data_line.length-1].trim();
		//console.log(end_str);
		if(end_str=='END')
		{
			cache.keys_obj={};
			for(let i in data_line)
			{
				this_line=data_line[i].trim();
				if(this_line)
				{
					let this_line_arr=this_line.split(':');
					let this_line_arr2=this_line.split(' ');
					if(this_line_arr.length>=3)
					{
						cache.keys_obj[this_line_arr[1]]=1;
						//STAT items:2:number 250000	
						if(this_line.indexOf("number")>0)
						{
							//得到每个key 列的条数
							cache.key_num[this_line_arr[1]]=Math.ceil(this_line_arr2[this_line_arr2.length-1]);
							
							//得到每个key 列的条数 对应的返回调试为0
							cache.key_back_num[this_line_arr[1]]=0;
							
						}

						
					}
				}
			}
			//已经取出keys 存在 cache.keys_obj,  
			cache.keys_obj_list=[];//存储为list
			for(let keys_num in cache.keys_obj)
			{
				cache.keys_obj_list.push(keys_num);
			}
			
			//
			if(cache.keys_obj_list.length==0)
			{
				goerr('无数据,操作失败');
			}
			
			//下一步发送数据的准备工作
			cache.send_now=0;
			cache.send_end=cache.keys_obj_list.length-1;
            this.get_keys_send();

		}else if(end_str=='ERROR'){
			//连接繁忙式异常 重新连接
			this.get_keys_obj_send();
		}else{
			console.error(cache.tag+' 未知异常');
		}
		
		
		
		
		
		

	}
	
	//002
	,get_keys_send:function()
	{
		cache.tag='get_keys';
        cache.data='';
		//console.log('get_keys_send');



		let keys_num=cache.keys_obj_list[cache.send_now];

        console.log('获取 #'+keys_num+' 所有key中');
		
		
		//发消息
		let statrt_num=cache.key_back_num[keys_num];
		let this_send=`stats cachedump ${keys_num} ${statrt_num} 0\r\n`;
		console.log(this_send);
		//console.log(cache);
		// ITEM views.decorators.cache.cache_header..cc7d9 [6 b; 1256056128 s] END
        //console.log(this_send);
        //console.log(cache);
		cache.send=this_send;
		tmp.client.write(this_send);
		
	}
	,get_keys_back:function(data)
	{
		//console.log('get_keys_back'); ITEM 867458042679102_LockState [1 b; 1610530568 s]
		//console.log(data);
        console.log('...校验获取到的key');
        addlog(data);
        //addlog(data);
		var data_line=data.split("\n");
		let end_str=data_line[data_line.length-1].trim();
		//console.log(end_str);
		if(end_str=='END')
		{
			
			//cache.keys_obj={};
            //cache.keys=[];
			var get_keys_back_num=0;
			for(let i in data_line)
			{
				this_line=data_line[i].trim();
				if(this_line)
				{
					let this_line_arr=this_line.split(' ');
					
					if(this_line_arr.length>=3)
					{
						get_keys_back_num=get_keys_back_num+1;
						let this_key=this_line_arr[1].trim();
						//console.log(this_key);
						cache.keys.push(this_key);

						//处理key的到期时间 ITEM 867458042679102_LockState [1 b; 1610530568 s]
                        try{
                            var this_key_exptime=this_line_arr[this_line_arr.length-2];
                            if(!this_key_exptime)
                            {
                                var this_key_exptime=0;
                            }
                        }catch(e){
                            var this_key_exptime=0;
                        }



                        var  reg_number=/[0-9]{1,20}/;

                        if(!reg_number.test(this_key_exptime))
                        {
                            var this_key_exptime=0;
                        }
                        this_key_exptime=Math.ceil(this_key_exptime);
                        if(this_key_exptime<time())
                        {
                            //小于备份的时间,为永久设置为0
                            this_key_exptime=0;
                        }


                        cache.key_exptime[this_key]=this_key_exptime;
                        //addlog(this_key);
					}
				}
			}
			
			
			
			//下一步发送数据的准备工作
			//常规 
			
			//分页处理
			//
			cache.key_back_num[cache.keys_obj_list[cache.send_now]]=cache.key_back_num[cache.keys_obj_list[cache.send_now]]+get_keys_back_num;
			console.log(cache.key_back_num[cache.keys_obj_list[cache.send_now]]);

			//取到的数据不足10行认为是 当前key列表结束, 结束后取下个key列表
			if(data_line.length<10)
			{
				
								
				//console.log(cache.send_now);
				if(cache.send_now!=cache.send_end)
				{

					cache.send_now=cache.send_now+1;
					//console.log(cache.send_now);
					this.get_keys_send();

				}else{
					//最后一个
					//下一步发送数据的准备工作
					cache.send_now=0;
					cache.send_end=cache.keys.length-1;
					tag_dump_pers(cache.keys);
					this.get_keys_value_send();
				}
			
				
			}else{
				this.get_keys_send();	
			}



		}else if(end_str=='ERROR'){
			//连接繁忙式异常 重新连接
			this.get_keys_obj_send();
		}else{
			goerr('未知异常');
		}
		
		
		

		
	}
	
	,get_keys_value_send:function()
	{
        //goerr('调试终止');
		/*let mem_save_txt=cache.keys.join("\r\n");
		//console.log(mem_save_txt);
		savetxt("mem_keys.txt",mem_save_txt,function(){
            goerr('调试终止');
		});
		console.log('get_keys_value_send');*/

        cache.tag='get_keys_value';
        cache.data='';
        //console.log('get_keys_value_send');

        let keys_num=cache.keys[cache.send_now];

        //处理百分比
        try{
            if(cache.per_obj[cache.send_now])
            {
                console.log('已完成 '+cache.per_obj[cache.send_now]);
            }
        }catch(e){}

        //console.log(cache.keys);
        //console.log(cache.send_now);
        //console.log(keys_num);
        //发消息
        let this_send=`get ${keys_num}\r\n`;
        //console.log(this_send);
        //console.log(cache);
		//addlog(this_send);
        cache.send=this_send;
        tmp.client.write(this_send);





	}

    ,get_keys_value_back:function(data)
    {
        //console.log('get_keys_value_back');
        //console.log(data);
		//VALUE 356802030658685_gpsstatus 0 99
		//VALUE       key			  flags len
		//add $key $flags $keyexp{$key} $len\r\n$val		$keyexp{$key}到期时间  倒数第2个字段 1610530568-》 ITEM 862868040756048_gsmstatus [23 b; 1610530568 s]
		/*
        add 123456_allstatus 0 1470385088 342
        1,2,3,4,5
		*/

    	let data_line=data.split("\n");
        let end_str=data_line[data_line.length-1].trim();
        let this_key=cache.keys[cache.send_now];
        //addlog(this_key+'\n->'+data);
        //console.log(end_str);
        if(end_str=='END')
        {

            /*cache.keys_obj={};
            cache.keys=[];
            for(let i in data_line)
            {
                this_line=data_line[i].trim();
                if(this_line)
                {
                    let this_line_arr=this_line.split(' ');

                    if(this_line_arr.length>=3)
                    {
                        let this_key=this_line_arr[1].trim();
                        //console.log(this_key);
                        cache.keys.push(this_key);
                    }
                }
            }*/

            //3行数据才是正常的
            var this_valueback_check_err=1;
            if(data_line.length==3)
			{
			    /*
                    VALUE 862032047380167_LockState 0 1
                    1
                    END

                    get 863753041517053_today
                    VALUE 863753041517053_today 0 58
                    1610804920,8699,54254.058594,85.610001,8.496506,1610804915
                    END

                */
                try{
                    var this_key_exptime=cache.key_exptime[this_key];
                    if(!this_key_exptime)
                    {
                        var this_key_exptime=0;
                    }
                }catch(e){
                    var this_key_exptime=0;

                }
				var this_value=data_line[1].trim();
                try{
                    this_value=this_value.replace(/[\x00-\x1f]+/g, '');

                    var this_value_end=this_value.substr(this_value.length-1,1);
                    //console.log(this_value_end);
                    if(chr('255')==this_value_end)
                    {
                        //console.log(this_value);
                        var this_value=this_value.substr(0,this_value.length-1);
                    }


                }catch(e){}




                var this_value_arr=data_line[0].split(' ');
                try{
                    if(!this_value_arr[2])
                    {
                        var this_flag=0;
                    }else{
                        var this_flag=this_value_arr[2];
                    }
                }catch(e){
                    var this_flag=0;
                }


				let this_back_str=`[****] ${this_key} <----> ${this_value} <----> ${this_key_exptime} <----> ${this_flag}`;
                var this_valueback_check_err=0;
				cache.output.push(this_back_str);
                //addlog(this_back_str);
			}
            if(this_valueback_check_err==1)
            {
                addlog(this_key+'\n'+data);
            }

            //下一步发送数据的准备工作
            //常规
            if(cache.send_now!=cache.send_end)
            {
                cache.send_now=cache.send_now+1;
                this.get_keys_value_send();
            }else{
                //最后一个
                //下一步发送数据的准备工作

                this.save_output();
            }



        }else if(end_str=='ERROR'){
            //连接繁忙式异常 重新连接
            this.get_keys_obj_send();
        }else{
            goerr('未知异常');
        }





    }
    ,save_output:function(){
		//console.log("save_output");
        let mem_save_txt=cache.output.join("\n");
        //console.log(mem_save_txt);
        savetxt($bak_file,mem_save_txt,function(){
            console.log("\n");
            console.log(new Date().Format("yyyy-MM-dd hh:mm:ss"));
            let this_log_num=cache.send_end+1;
            console.log("总计备份: "+this_log_num);
            goerr('备份成功');
        });

	}

    ,set_keys:function()
    {
        //console.log('get_stats_send');
        cache.tag='set_keys';
        //从备份文件读出数据,进行set

        var bak_str=readtxt($bak_file);
        var bak_str_arr=bak_str.split('[****]');
        var keys_setvalue_list=[];
        for(var i in bak_str_arr)
        {
            var this_str_one=bak_str_arr[i].trim();
            var this_str_one_arr=this_str_one.split("<---->");
            if(this_str_one_arr.length>2)
            {
                //console.log(this_str_one_arr);
                var this_key=this_str_one_arr[0].trim();
                var this_value=this_str_one_arr[1].trim()+'';
                try{
                    var this_exptime=this_str_one_arr[2].trim();
                    if(!this_exptime)
                    {
                        var this_exptime=0;
                    }
                }catch(e){
                    var this_exptime=0;
                }


                try{
                    var this_flag=this_str_one_arr[3].trim();
                    if(!this_flag)
                    {
                        var this_flag=0;
                    }
                }catch(e){
                    var this_flag=0;
                }

                if(this_exptime==0)
                {
                    var this_time=0;
                }else{
                    var this_time=this_exptime-time();
                }
                if(this_time<0)
                {
                    this_time=0;
                }
                var this_length=this_value.length;
                var this_set_html=`set ${this_key}  ${this_flag}  ${this_time}  ${this_length}\r\n${this_value}\r\n`;
                var this_set_obj={
                    key:this_key
                    ,send:this_set_html
                };
                keys_setvalue_list.push(this_set_obj);
                cache.keys_setvalue_num[this_key]=0;//发送set的次数
            }


        }
        cache.keys_setvalue_list=keys_setvalue_list;
        if(keys_setvalue_list.length==0)
        {
            goerr('备份文件无合适数据set');
        }
        tag_dump_pers(cache.keys_setvalue_list);
        //console.log(keys_setvalue_list);

        //下一步发送数据的准备工作
        cache.send_now=0;
        cache.send_end=cache.keys_setvalue_list.length-1;

        this.set_keys_value_send()




    }


    ,set_keys_value_send:function()
    {

        //console.log('set_keys_value_send');

        cache.tag='set_keys_value';
        cache.data='';


        //
        let this_key=cache.keys_setvalue_list[cache.send_now].key;
        let this_send=cache.keys_setvalue_list[cache.send_now].send;



        //console.log(cache.send_now);
        //处理百分比
        try{
            if(cache.per_obj[cache.send_now])
            {
                console.log('已完成 '+cache.per_obj[cache.send_now]);
            }
        }catch(e){}

        cache.keys_setvalue_num[this_key]=cache.keys_setvalue_num[this_key]+1;
        //console.log(this_send);
        //console.log(cache);
        //addlog(this_send);
        cache.send=this_send;
        tmp.client.write(this_send);





    }

    ,set_keys_value_back:function(data)
    {


        let data_line=data.split("\n");
        let end_str=data_line[data_line.length-1].trim();
        let this_key=cache.keys_setvalue_list[cache.send_now].key;
        //addlog(this_key+'\n->'+data);
        //console.log(end_str);
        if(end_str=='STORED')
        {


            //console.log(this_key);

            //下一步发送数据的准备工作
            //常规
            if(cache.send_now!=cache.send_end && cache.keys_setvalue_num[this_key]<cache.keys_setvalue_maxnum)
            {
                cache.send_now=cache.send_now+1;
                this.set_keys_value_send();
            }else{
                //最后一个
                //下一步发送数据的准备工作

                this.set_output();
            }



        }else if(end_str=='ERROR'){
            //连接繁忙式异常 重新连接
            this.get_keys_obj_send();
        }else{
            goerr('未知异常');
        }





    }

    ,set_output:function(){
        //console.log("set_output");
        console.log("\n");
        console.log(new Date().Format("yyyy-MM-dd hh:mm:ss"));
        let this_log_num=cache.send_end+1;
        console.log("总计set: "+this_log_num);
        goerr('SET成功');


    }
	
	,set_keys_nodememcache:function()
    {


		console.log('set_keys_value_nodememcache');
        cache.tag='set_keys_value_nodememcache';
        //从备份文件读出数据,进行set

        var bak_str=readtxt($bak_file);
        var bak_str_arr=bak_str.split('[****]');
        var keys_setvalue_list=[];
        for(var i in bak_str_arr)
        {
            var this_str_one=bak_str_arr[i].trim();
            var this_str_one_arr=this_str_one.split("<---->");
            if(this_str_one_arr.length>2)
            {
                //console.log(this_str_one_arr);
                var this_key=this_str_one_arr[0].trim();
                var this_value=this_str_one_arr[1].trim()+'';
                try{
                    var this_exptime=this_str_one_arr[2].trim();
                    if(!this_exptime)
                    {
                        var this_exptime=0;
                    }
                }catch(e){
                    var this_exptime=0;
                }


                try{
                    var this_flag=this_str_one_arr[3].trim();
                    if(!this_flag)
                    {
                        var this_flag=0;
                    }
                }catch(e){
                    var this_flag=0;
                }

                if(this_exptime==0)
                {
                    var this_time=0;
                }else{
                    var this_time=this_exptime-time();
                }
                if(this_time<0)
                {
                    this_time=0;
                }
                var this_length=this_value.length;
                var this_set_html=`set ${this_key}  ${this_flag}  ${this_time}  ${this_length}\r\n${this_value}\r\n`;
                var this_set_obj={
                    key:this_key
                    ,send:this_set_html
					,time:this_time
					,value:this_value
					,flag:this_flag
                };
                keys_setvalue_list.push(this_set_obj);
                cache.keys_setvalue_num[this_key]=0;//发送set的次数
            }


        }
        cache.keys_setvalue_list=keys_setvalue_list;
        if(keys_setvalue_list.length==0)
        {
            goerr('备份文件无合适数据set');
        }
        tag_dump_pers(cache.keys_setvalue_list);
        //console.log(keys_setvalue_list);

        //下一步发送数据的准备工作
        cache.send_now=0;
        cache.send_end=cache.keys_setvalue_list.length-1;

        this.set_keys_value_nodememcache();




    }

    ,set_keys_value_nodememcache:function()
    {

        //console.log('set_keys_value_nodememcache');

        cache.tag='set_keys_value_nodememcache';
        cache.data='';


        //
        let this_key=cache.keys_setvalue_list[cache.send_now].key;
        let this_value=cache.keys_setvalue_list[cache.send_now].value;

		let this_time=cache.keys_setvalue_list[cache.send_now].time;

        //console.log(cache.send_now);
        //处理百分比
        try{
            if(cache.per_obj[cache.send_now])
            {
                console.log('已完成 '+cache.per_obj[cache.send_now]);
            }
        }catch(e){}

        cache.keys_setvalue_num[this_key]=cache.keys_setvalue_num[this_key]+1;
        //console.log(this_send);
        //console.log(cache);
        //addlog(this_send);
        go_nodememcache(cache.keys_setvalue_list[cache.send_now],function(result,obj){
			
			//console.log(obj.key);
			//console.log(result);
			//下一步发送数据的准备工作
            //常规
            if(cache.send_now!=cache.send_end && cache.keys_setvalue_num[this_key]<cache.keys_setvalue_maxnum)
            {
                cache.send_now=cache.send_now+1;
                action.set_keys_value_nodememcache();
            }else{
                //最后一个
                //下一步发送数据的准备工作

                action.set_output();
            }
			
			
			
		});



    }	
	

};



console.log(new Date().Format("yyyy-MM-dd hh:mm:ss"));

var net = require('net');
var socket=net.Socket();
socket.setEncoding('ascii');
socket.setNoDelay(false);
var client = socket.connect({host:$mem_ip,port: $mem_port}, function() {
	tmp.client=client;
    console.log('\n');
   console.log('连接到MEMCACHE服务器!');
   if($type=="bak" || $type=="dump")
   {
	//备份

	   action.get_keys_obj_send();
	   //client.write('stats items\n');
   }else if($type=='set') {
       action.set_keys_nodememcache();
   }else if($type=='stat') {
       action.get_stats_send();
   }else {
   		go_help();
   }
});
client.on('data', function(data) {
		cache.active_time=time();//更新收到数据时间
        //console.log(data);
		var end_str=data.substr(data.length-1,1);
		end_str=end_str.charCodeAt();
		//console.log(end_str);
		
		var end_str2=data.substr(data.length-2,1);
		end_str2=end_str2.charCodeAt();
		//console.log(end_str2);


		var data_bak=data.trim();

		
		let check_end=data_bak.substr(data_bak.length-3,3);
		let check_error=data_bak.substr(data_bak.length-5,5);
        let check_stored=data_bak.substr(data_bak.length-6,6);
		
		//console.log(check_end);
		//console.log(check_error);
		
		cache.data=cache.data+data;
		
		if( (check_end=='END' || check_error=='ERROR' || check_stored=='STORED') && end_str==10 && end_str2==13)
		{
			//console.log('ok');
            var cache_data=cache.data.trim();
			action[cache.tag+'_back'](cache_data);
				
			try{
			}catch(e){}	
		}
		

	

   //client.end();
});
client.on('end', function() {
    console.log('\n');
   console.log('结束与MEMCACHE服务器的连接');
});
client.on('error', function() {
    console.log('\n');
   console.error('断开与MEMCACHE服务器的连接');
});
JavaScript
操作方法
[状态] node mem.js 127.0.0.1:11555
[备份] node mem.js 127.0.0.1:11555 dump bak_01.txt
[恢复] node mem.js 127.0.0.1:11555 set bak_01.txt

需要修改memcache源码,支持下面命令多了个 statrt_num,分页的开始值

stats cachedump ${keys_num} ${statrt_num} 0

标签: nodejsmemcache
阅读剩余的95%

相关文章

取巧快速加水印

收到个紧急需求,由于我们客户主要是学校。我们开发的主要是教学软件,但是也开发教学课件。这次就是交付的教学课件,用在别的系统上。学校提需求需要在课件上加水印。不知道是不是看了钉钉等软件带来的灵感,要斜斜...

vb.net加密狗方案

先前做过e语言加密狗,被识别为病毒。现在 挑战vb.net对vb.net完全不熟悉,于是面向百度编程。好在加密狗厂家提供了vb.net的demo,我要做的事情就是让其他程序能够调用。思路就是直接编译成...

如何判断一个经纬度是哪个省?

需求是这样的,有个卖gps防盗器的公司,需要分析出用户去年一年内经过了那些城市?假设有10万个用户,每个用户有100万个轨迹点。我们怎么分析呢?常规方法是一个点一个点的分析,那就是10w*100w=1...

h5的横屏适配

h5的横屏适配

最近遇到一个问题,我们开发的软件是横屏软件,因客户群体主要是学校,就是使用者是老师和学生。本来软件设计的是电脑机房里用,现在学校希望手机也可以用。结果手机用起来就是这个现象。老师提意见,说字太小看不清...

多种图片生成,打包接口传递

前面介绍了ImageMagick这个工具,可以将pdf转成png。这里再结合先前工作的实际需求补充一点相关知识。原先入职的是一家摩托车金融公司,就是借款买摩托车。公司对接了一些资金方,有这么个需求,需...

html5-声音视频自动播放的坑

因为从事的是教学软件的开发,不知何年何月开始声音、视频不支持自动播放了。必须点一个按钮才能播放。教学类软件很多都是有动画的,像播放器一样,从头开始慢慢播放,可以理解为n帧,但是因为程序开发不是视频制作...