Oct
29
用框架的cache时发现,command和controller设置的cache互相之间居然是独立的,对于CFileCache,通过grep可以在 app/runtime/cache 下面看到,相同的key在两边set以后,会存在两个不同的文件里面:显然是在hash得到cache key的时候用了一个额外的串。
没办法,只能去翻Yii的源码,在 framework/cache/CCache.php 可以看到get/set方法是调用了 generateUniqueKey 来生成cache key;该方法用到的keyPrefix 是取值于 "Yii::app()->getId()" 。追过去,在 framework/base/CApplication.php 里面可以看到,这个getId()的实现是"crc32($this->getBasePath().$this->name)"。
于是去看了一下,果然 config 下面 main.php 和 console.php 配置的 name 不同,所以框架把它们认为是两个project。改成一样,就解决了。
但是……
还有一个隐藏得更深的坑:
缓存文件(例如runtime/cache/04/51/045113ce863440795dab03b29a4ec384.bin)里的内容是这样的:
也就是说,这个缓存在遇到两个md5相同的key时,无法做出区分!
这个只能看命了。
UPDATE:
缓存冲突问题,虽然不能彻底解决,但是可以通过简单的包装,把原先set的value换成 {'key': ..., 'value': value}, 然后在get的时候检查一下是否匹配,不匹配的话简单丢弃,这样至少不会遇到莫名其妙的BUG。
没办法,只能去翻Yii的源码,在 framework/cache/CCache.php 可以看到get/set方法是调用了 generateUniqueKey 来生成cache key;该方法用到的keyPrefix 是取值于 "Yii::app()->getId()" 。追过去,在 framework/base/CApplication.php 里面可以看到,这个getId()的实现是"crc32($this->getBasePath().$this->name)"。
于是去看了一下,果然 config 下面 main.php 和 console.php 配置的 name 不同,所以框架把它们认为是两个project。改成一样,就解决了。
但是……
还有一个隐藏得更深的坑:
缓存文件(例如runtime/cache/04/51/045113ce863440795dab03b29a4ec384.bin)里的内容是这样的:
引用
a:2:{i:0;s:26:"2015-10-29 18:28:03command";i:1;N;}
也就是说,这个缓存在遇到两个md5相同的key时,无法做出区分!
这个只能看命了。
UPDATE:
缓存冲突问题,虽然不能彻底解决,但是可以通过简单的包装,把原先set的value换成 {'key': ..., 'value': value}, 然后在get的时候检查一下是否匹配,不匹配的话简单丢弃,这样至少不会遇到莫名其妙的BUG。
Oct
29
转置二维数组:
utf-8字符串转为utf-8字符数组:
按显示宽度截取utf-8字符串
让进程在后台运行(detached process),出乎意料地简单
function transpose($array) {
array_unshift($array, null);
return call_user_func_array('array_map', $array);
}
array_unshift($array, null);
return call_user_func_array('array_map', $array);
}
utf-8字符串转为utf-8字符数组:
function utf8_str2arr($str)
{
preg_match_all("/./u", $str, $arr);
return $arr[0];
}
{
preg_match_all("/./u", $str, $arr);
return $arr[0];
}
按显示宽度截取utf-8字符串
function substr_width($str, $start, $width)
{
$arr = utf8_str2arr($str);
$arr_ret = [];
$i = 0;
while ($width > 0 and $i < count($arr))
{
$arr_ret[] = $arr[$start + $i];
if (strlen($arr_ret[$i]) == 1) //ascii,width=1
$width -= 1;
else
$width -= 2;
$i++;
}
if ($width < 0)
array_pop($arr_ret);
return join('', $arr_ret);
}
{
$arr = utf8_str2arr($str);
$arr_ret = [];
$i = 0;
while ($width > 0 and $i < count($arr))
{
$arr_ret[] = $arr[$start + $i];
if (strlen($arr_ret[$i]) == 1) //ascii,width=1
$width -= 1;
else
$width -= 2;
$i++;
}
if ($width < 0)
array_pop($arr_ret);
return join('', $arr_ret);
}
让进程在后台运行(detached process),出乎意料地简单
pclose(popen("nohup $cmd &", 'r'));
Oct
16
在Windows下用惯了Secure CRT的Clone Session功能,切换到mac下面,还真有点怀念。于是搜了一下,发现达到类似的效果倒是也不难。
1. mkdir ~/.ssh/cm_socket
2. 创建 ~/.ssh/config
Host *
ControlMaster auto
ControlPath ~/.ssh/cm_socket/%r@%h:%p
3. 之后只要是相同的 user@host:port 都会共用一个tcp connection,不需要再输入密码了。
p.s. 补充说明一下,通常来说,能登录服务器也就意味着可以建立信任关系,那么clone session的意义就减少了很多,但是仍然有两个优势:
1. 类似B公司的relay机器,必须使用token认证才能登录的,信任关系不能满足需求(Google Authenticator这样的两步认证方案也类似)
2. 对于延迟比较高的机器,直接复用tcp connection,可以减少相当多的时间(tcp三次握手、ssh认证的各种交互等)。
1. mkdir ~/.ssh/cm_socket
2. 创建 ~/.ssh/config
Host *
ControlMaster auto
ControlPath ~/.ssh/cm_socket/%r@%h:%p
3. 之后只要是相同的 user@host:port 都会共用一个tcp connection,不需要再输入密码了。
p.s. 补充说明一下,通常来说,能登录服务器也就意味着可以建立信任关系,那么clone session的意义就减少了很多,但是仍然有两个优势:
1. 类似B公司的relay机器,必须使用token认证才能登录的,信任关系不能满足需求(Google Authenticator这样的两步认证方案也类似)
2. 对于延迟比较高的机器,直接复用tcp connection,可以减少相当多的时间(tcp三次握手、ssh认证的各种交互等)。