为了实现Cassandra的LongType,必须编写代码实现将Unix时间戳记转化为64位长整型,并以低位在先的binary方式保存在变量中。
在网上找了一些解决方案,大体上都是通过第三方扩展,或者通过将低32位和高32位分开保存,再做处理的。有些方案的结果根本就是错误的。
还好,目前应对的问题仅是Unix时间戳记,而且microtime()函数是将小数点前面的部分和后面的部分分开保存的,这一切都有利于实现这个函数。
首先,和一般的算法一样,将高低32位分开。由于microtime返回的字符串实际代表的浮点数小数部分有8位十进制位,而Cassandra常用的只有6位,因此后两位就在算法中忽略掉。将除数的小数点也向前6位,这样保证得到的结果与直接的整型运算相符。注意:这样做的前提是,我们预先知道Unix时间戳记的高32位代表的数字不会溢出。
$iHi = (int)($sec / 4294.967296);
然后,取得剩余的浮点数,并乘以100,为下一步做准备。
$fRemain = (float)(($sec - $iHi * 4294.967296 + $usec) * 100);
考虑到这是个64位长整型,其低32位只能是无符号整数,PHP也没有办法处理。因此,需要暂时提取中间的16位,保证数据正确。本应该除以0.065536,但是之前已经乘以100了,这里就直接除以6.5536。
$iMed = (int)($fRemain / 6.5536);
继续获取剩余的浮点数。
$fRemain = (float)($fRemain - $iMed * 6.5536);
那么低16位就是剩余数字乘以10000了。
$iLow = (int)($fRemain * 10000);
最后,按照低位在前的方式打包所有部分,并串接起来,得到的变量就是我们要的长整型数据了。这一步是力求接近Cassandra的实现代码,目前还没有考虑Memcache协议是否允许key中包含0×00。如果不允许的话,在保存的时候还需要使用bin2hex转化为字符串。
以下为全部代码:
function get_long_timestamp($sMicrotime = ”) {
if(!$sMicrotime) $sMicrotime = microtime();
list($usec, $sec) = explode(” “, $sMicrotime);
$iHi = (int)($sec / 4294.967296);
$fRemain = (float)(($sec - $iHi * 4294.967296 + $usec) * 100);
$iMed = (int)($fRemain / 6.5536);
$fRemain = (float)($fRemain - $iMed * 6.5536);
$iLow = (int)($fRemain * 10000);
return (pack(”v”, $iLow) . pack(”v”, $iMed) . pack(”V”, $iHi));
}
$sMicrotime = microtime();
var_dump($sMicrotime);
var_dump(bin2hex(get_long_timestamp($sMicrotime)));
下面可能会研究Memcache协议的key中是否允许出现0×00。