Node_redis对数组支持的BUG

做微信公众平台的时候发现Node_redis(https://github.com/mranney/node_redis)一个严重BUG
执行redis.lpush(‘mylist’,[‘a’,’b’,’c’],callback)的时候,预计返回

mylist
a
b
c

实际返回

mylist
a,b,c

Github已经有人提出过这个问题

https://github.com/mranney/node_redis/issues/369#issuecomment-13050944

产生原因

所有的client.COMMAND会调用client.send_command()

RedisClient.prototype[command] = function (args, callback) {
    if (Array.isArray(args) && typeof callback === "function") {
        return this.send_command(command, args, callback);
    } else {
        return this.send_command(command, to_array(arguments));
    }
};

调用client.COMMAND的时候

client.COMMAND(key, ["arg1", "arg2", "arg3"], callback);

会被解析成

client.send_command(COMMAND, [key, ["arg1", "arg2", "arg3"]], callback);

send_command()有如下段落

    for (i = 0, il = args.length, arg; i < il; i += 1) {
        arg = args[i];
        if (typeof arg !== "string") {
            arg = String(arg);
        }
        command_str += "$" + Buffer.byteLength(arg) + "\r\n" + arg + "\r\n";
    }

示例中循环到第二次 arg = ["arg1", "arg2", "arg3"] ,会被String()强制转换为"arg, arg2, arg3",产生BUG。

解决方法

直接调用

client.send_command(COMMAND, [key, "arg1", "arg2", "arg3"], callback);

或者将key包含到数组里面

client.COMMAND([key, "arg1", "arg2", "arg3"], callback);

吐个槽

既然都知道原因了,2013年2月的issue为什么到现在都还没解决!!

系统引导流程、重建和Grub

手抖格式化了硬盘,好在及时停止,只是引导被破坏。原系统中有Win7+Ubuntu双系统,Win7在/dev/sda1,Linux在/dev/sda7。重装引导的时候出了不少问题,也得到了很多新的认识。

Grub和Grub2

Grub有Grub和Grub2。Grub2在10年前已经发布,目前预装在了大多数发行版上。网上各种教程多为Grub的而不是Grub2。
Grub和Grub2有很大区别,经常碰到的有:

  • /boot/grub/menu.lst被/boot/grub/grub.cfg所取代
  • update-grub被grub-mkconfig -o /boot/grub/grub.cfg取代
  • Grub中加载内核命令kernel在Grub2中有相似的命令linux

已经入过一次坑,请大家明鉴。

乱糟糟的中文wiki:http://linux-wiki.cn/wiki/zh-hans/Grub2%E9%85%8D%E7%BD%AE
grub和grub2的区别:http://lesca.me/archives/differences-between-grub-and-grub2.html

MBR和各种启动器的关系

each disk has an mbr (master boot record) or vbr (volume boot record)
– a partition does not have an mbr or vbr

the mbr is in the first 512 bytes of a disk and is not normally
accessible

the mbr (basically) holds the information for your disk and partitions
and where to find the boot files

bcdedit in win7 and vista is the boot configuration data editor, this
has replaced ntldr (new technology loader) that is in xp and w2k
linux uses grub (grand unified bootloader) or lilo (linux loader)

all 4 of these write to your mbr so your mbr can access the boot
configuration file (boot.ini in xp/w2k, menu.lst for grub legacy or
grub.conf for grub2 in linux, etc) and allow the system to boot,

windows bootloaders do not recognise other systems so cannot boot
non-windows systems, grub can be installed on its own and can boot
any operating system,
原文:http://answers.yahoo.com/question/index?qid=20100902034736AAUYSXC

大致翻译

每块硬盘都有一个MBR(Master Boot Record,主引导记录)或者VBR(Volume Boot Record,卷引导记录)。
MBR在磁盘的头512字节(这就是为什么低级格式化磁盘造成MBR损坏的原因),保存了磁盘和分区的启动信息。
winxp、win2k使用ntldr(New Technology Loader),Win7、Vista使用bcdedit来作为引导编辑器,Linux一般使用grub、lilo等。
以上这四个工具会写MBR来引导启动相应的操作系统。但是Win的引导器只能引导Win的操作系统,Linux的例如grub2可以引导Win、Linux甚至Mac。

MBR由三个部分组成:

  1. 第1-446字节:调用操作系统的机器码
  2. 第447-510字节:分区表(Partition table)
  3. 第511-512字节:主引导记录签名(0x55和0xAA)

http://zh.wikipedia.org/wiki/MBR

启动流程

  1. BIOS
  2. MBR中的第一部分机器码执行
  3. 各种启动器(grub、lilo……)
  4. 操作系统等

这样看来系统分区设为活动分区并不是必须的,这主要视引导程序而定,有些引导程序例如Grub4Dos仅仅遍历所有分区并运行第一个找到的引导器grldr。同样,grub写入MBR中的程序会搜寻逻辑分区,所以将grub主程序安装在逻辑分区(/dev/sda7)里面依然能够正常启动。

Grub2重建引导

Grub2中重建引导命令

grub-install --root-directory=/ /dev/sda
--root-directory是指安装的位置,一般安装在分区根目录下
/dev/sda是MBR的写入磁盘,是整个磁盘而不是分区

例如单硬盘机器Linux安装在/dev/sda7:

mount /dev/sda7 /mnt
grub-install --root-directory=/mnt/ /dev/sda

这样可以将Grub2安装在Linux分区里面,当然也可以安装在其他分区。Grub2会自动搜索NTFS分区, 理论上安装好后不用配置就可以引导Windows。(有些地方似乎是grub2-install)
很多教程将命令写作

grub-install --boot-directory=/boot

不知道是否有这个用法,但是我没成功。
另外

grub-update 自动更新启动项目列表,添加有效操作系统(有的地方写作update-grub)

重建引导都干了什么

执行grub-install之后会重写MBR的第一部分,这样计算机启动的时候就会执行重写过后的机器码,这段机器码会将控制权交给grub主程序,这里是/dev/sda7里的/boot/grub(当然/boot/grub也会在install的时候重新安装)。开始第二阶段引导加载。

Linux 引导过程内幕https://www.ibm.com/developerworks/cn/linux/l-linuxboot/

让织梦缩略图自适应裁剪

Ecjtu.net有三个页面需要调用同一个文章的缩略图,但大小比例都不一样。用如下方法实现缩略图自动裁切。

需要PHP安装GD库,http://www.php.net/manual/zh/intro.image.php

代码

/include/extend.func.php里添加thumb()函数:

function thumb($imgurl, $width, $height)
{
    global $cfg_mainsite,$cfg_multi_site;
    $thumb = eregi("http://",$imgurl)?str_replace($cfg_mainsite,'',$imgurl):$imgurl; 
    list($thumbname,$extname) = explode('.',$thumb);
    $newthumb = $thumbname.'_'.$width.'_'.$height.'.'.$extname;
    if(!$thumbname || !$extname || !file_exists(DEDEROOT.$thumb)) return $imgurl;
    if(!file_exists(DEDEROOT.$newthumb))
    {
        include_once DEDEINC.'/image.func.php';
        $src_im = imagecreatefromjpeg(DEDEROOT.$thumb);
        $dst_im = imagecreatetruecolor($width, $height);
        $width_im = imagesx($src_im);
        $height_im = imagesy($src_im);
        if($width_im/$height_im < $width/$height)
        {
            $tmp = ($height_im-$width_im*($height/$width))/2;
            imagecopyresampled($dst_im, $src_im, 0, 0, 0, $tmp, $width, $height, $width_im, $height_im - $tmp*2);
        }
        else
        {
            $tmp = ($width_im-$height_im*($width/$height))/2;
            imagecopyresampled($dst_im, $src_im, 0, 0, $tmp, 0, $width, $height, $width_im - $tmp*2, $height_im);
        }
        imagejpeg($dst_im, DEDEROOT.$newthumb, 100);
        imagedestroy($dst_im);
        imagedestroy($src_im);
    }
    return $cfg_multi_site=='Y'?$cfg_mainsite.$newthumb:$newthumb;
}

调用

在任何调用缩略图的时候:

[field:picname function='thumb(@me,590,310)'/]
第二个第三个参数分别为宽高

规则

调用缩略图的时候首先查看缩略图目录是否有相应大小裁切过的图片,有就直接返回,没有就在同目录下生成并返回。
生成的缩略图命名规则:

原缩略图名_宽_高.xxx
例:142_1321254421_590_310.jpg

裁切规则:

  • 保持需要的比例
  • 尽可能大的保留图片
  • 超出尺寸部分裁剪两边保留中间

注意

相应尺寸的缩略图生成之后就永远不会被改变,因此某些特殊情况下可能需要你手动删除。