关于PHP的memcache模块的delete方法

【 可直接参看: http://phpor.net/blog/post/888 】

上篇文章解决了PHP的Memcache 模块的get方法不区分连接失败NOT FOUND, 今天说一下delete方法不区分NOT FOUND和连接失败的处理办法。

这次的修改不同上次,虽然delete也有第二个参数,但是第二个参数不是引用(当然可以修改成引用,只是稍微麻烦一点);根据delete的特点,不妨将返回值修改为整型(long型); 代码如下:
==== memcache.c =======

  1. PHP_FUNCTION(memcache_delete)
  2. {
  3.     if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) {
  4.         RETURN_LONG(-1); // 此处修改
  5.     }
  6.     if (mmc_prepare_key_ex(key, key_len, key_tmp, &key_tmp_len TSRMLS_CC) != MMC_OK) {
  7.         RETURN_LONG(-1);  // 此处修改
  8.     }
  9.     while (result < 0 && (mmc = mmc_pool_find(pool, key_tmp, key_tmp_len TSRMLS_CC)) != NULL) {
  10.         if ((result = mmc_delete(mmc, key_tmp, key_tmp_len, time TSRMLS_CC)) < 0) {
  11.             mmc_server_failure(mmc TSRMLS_CC);
  12.         }      
  13.     }
  14.     if (result > 0) {
  15.         RETURN_LONG(1); // delete OK
  16.     } elseif(result == 0) {
  17.         RETURN_LONG(0); // not found
  18.     }
  19.     RETURN_LONG(-1); // connect fail
  20. }

测试代码如下:

  1. <?php
  2. $m = new Memcache();
  3. $m->addServer(“127.0.0.1”, 11211); // this is available
  4. $result = $m->delete(“noexists”);
  5. var_dump($result);
  6. $m->set(“exists”,“I am here”,0,600);
  7. $result = $m->delete(“exists”);
  8. var_dump($result);
  9. $m = new Memcache();
  10. $m->addServer(“127.0.0.1”, 11214); // this is available
  11. $result = $m->delete(“noexists”);
  12. var_dump($result);

输出:
int(0)
int(1)
int(-1)

这样修改以后,确实挺好用的,但是,和原来的用法已经不兼容了,除非你原来根本就不判断返回值。

关于PHP的memcache模块的一点修改

缘起

PHP连接Memcached一般有两个模块可以使用: libmemcached和memcache;
libmemcached是不支持PHP的长连接的,但是这个模块对各种错误的处理支持的比较好,如果不要求长连接的话,一般使用该模块。
memcache模块自从我开始使用(3年前)用的是2.2.4版本,到现在stable才到2.2.6; 开发极慢,而且最为让人诟病的一个bug就是: get($key)的返回值对于连接失败和NOT FOUND都是返回false的,以至于我无法知道究竟是哪种错误;如果我不关心二者的区别也就算了,对于必须(或者非常有必要)区别二者的话,只好选择使用libmemcached了。

现在遇到的问题是: 我既要区分连接失败和NOT FOUND,我有需要使用长连接,只好去看memcache的源码了。

解决办法

【可直接参看: http://phpor.net/blog/post/888 】

对于memcache的get方法有第二个参数,这个很少使用(而且用的时候也很是不爽的),就是flag参数,该参数为引用传递,旨在回传memcache中的存储标识,而且比较常用的标识就只有几个(如:压缩);看了一下源码,不妨通过该参数来回传失败的类型,如果是NOT FOUND,则可以将该参数设置一个特殊的标识,具体修改代码如下:

==== memcache.c ===

  1. int mmc_exec_retrieval_cmd(mmc_pool_t *pool, const char *key, int key_len, 
  2.         zval **return_value, zval *return_flags TSRMLS_DC) /* {{{ */
  3. {
  4.     mmc_t *mmc;
  5.     char *command, *value; 
  6.         /* not found */
  7.             if (result == 0) { 
  8.                 flags |= 1<<30;
  9.                 ZVAL_FALSE(*return_value);
  10.             }
  11. }

下面是一个测试脚本:

  1. <?php
  2. $m = new Memcache();
  3. $m->addServer(“127.0.0.1”, 11211); // this is available
  4. //$m->addServer(“127.0.0.1”, 11219); //this is unavailable
  5. define(“E_MC_NO_FOUND”, 1<<30); 
  6. $flag=0;  // 这个一定要有值,否则是不会回传$flag的,大概这是一个bug吧
  7. $result = $m->get(“noexists”,$flag);
  8. if($result === false) {
  9.     if ($flag & E_MC_NO_FOUND) {
  10.         echo “not found\n”;
  11.     } else {
  12.         echo “connect error\n”;
  13.     }
  14. }
  15. echo “flag:”.decbin($flag);

遗留问题:
为什么$flag 不设置一个值就不能回传内部的值,究竟源码错在了何处?

VIM 编程时括号的自动扩展

不解释了,把下面代码贴到.vimrc文件中就行了,然后,重新打开vim,写一个函数试试,我感觉还不错的…

 
  1. :inoremap <S-ENTER> <c-r>=SkipPair()<CR>
  2. :inoremap <S-SPACE> <ESC>la
  3. :inoremap <C-ENTER> <ESC>A;<CR>
  4. :inoremap ( ()<ESC>i
  5. :inoremap ) <c-r>=ClosePair(‘)’)<CR>
  6. :inoremap { <c-r>=ClsoeBrace()<CR>
  7. :inoremap } <c-r>=ClosePair(‘}’)<CR>
  8. :inoremap [ []<ESC>i
  9. :inoremap ] <c-r>=ClosePair(‘]’)<CR>
  10. :inoremap ;; <ESC>A;<CR>
  11. function ClosePair(char)
  12.    if getline(‘.’)[col(‘.’) – 1] == a:char
  13.       return "\<Right>"
  14.    else
  15.       return a:char
  16.    endif
  17. endf
  18. function Semicolon()
  19.    "echo getline(‘.’)[col(‘.’)]
  20.    if getline(‘.’)[col(‘.’)] == ‘)’
  21.       return "<ESC>A;"
  22.    elseif getline(‘.’)[col(‘.’)] == ‘}’
  23.       return "\<ESC>A;"
  24.    elseif getline(‘.’)[col(‘.’)] == ‘]’
  25.       return "\<ESC>A;"
  26.    else
  27.       return ";"
  28.    endif
  29. endf
  30. function SkipPair()
  31.    if getline(‘.’)[col(‘.’) – 1] == ‘)’
  32.       return "\<ESC>o"
  33.    else
  34.       normal j
  35.       let curline = line(‘.’)
  36.       let nxtline = curline
  37.       while curline == nxtline
  38.          if getline(‘.’)[col(‘.’) – 1] == ‘}’
  39.             normal j
  40.             let nxtline = nxtline + 1
  41.             let curline = line(‘.’)
  42.             continue
  43.          else
  44.             return "\<ESC>i"
  45.          endif
  46.          
  47.       endwhile
  48.       return "\<ESC>o"
  49.    endif
  50. endf
  51. function ClsoeBrace()
  52.    if getline(‘.’)[col(‘.’) – 2] == ‘=’
  53.       return "{}\<ESC>i"
  54.    elseif getline(‘.’)[col(‘.’) – 3] == ‘=’
  55.       return "{}\<ESC>i"
  56.    elseif getline(‘.’)[col(‘.’) – 1] == ‘{‘
  57.       return "{}\<ESC>i"
  58.    elseif getline(‘.’)[col(‘.’) – 2] == ‘{‘
  59.       return "{}\<ESC>i"
  60.    elseif getline(‘.’)[col(‘.’) – 2] == ‘,’
  61.       return "{}\<ESC>i"
  62.    elseif getline(‘.’)[col(‘.’) – 3] == ‘,’
  63.       return "{}\<ESC>i"
  64.    else
  65.       return "{\<ENTER>}\<ESC>O"
  66.    endif
  67. endf

C++学习之 virtual 关键字

观看一个例子:

 
  1. #include <iostream>
  2. using namespace std;
  3. class A{
  4.     public:
  5.         virtual void say() {
  6.             cout<<"A say: "<<endl;
  7.         }
  8. };
  9. class B :public A{
  10.     public:
  11.         void say() {
  12.             cout<<"B say: "<<endl;
  13.         }
  14. };
  15. void testVirtual(A& a) {
  16.     a.say();
  17. }
  18. int main(void) {
  19.     B b;
  20.     //b.say("hello B");
  21.     testVirtual(b);
  22.     return 0;
  23. }

1. 注意 第6行的virtual关键字和第18行的引用传参
2. 现在的结果是 "B say:";
3. 如果去掉virtual关键字,或者传参的时候不使用引用传参,则,输出的结果都将是: "A say:"
4. 这种语法现象叫 upcast
5. c++ 中class声明类,要以分号结束
6. 参考资料: 《C++编程思想》之 第15章 多态性和虚函数

启动gvim时自动最大化窗口的方法

根据帮助文档,gvim在windows下的最大化是通过模拟打开窗口菜单并点击最大化菜单项实现的,而在Linux下的方法较为灵活。

下面的方法是在vim中通过调用wmctrl实现最大化的方法:

好久没看c++了

好久没看c++了,以为自己还能看明白,今天看了kyototycoon中的一个类,遇到了好几个知识点:

 
  1. // plug-in server driver
  2. class PlugInDriver : public kc::Thread {
  3.  public:
  4.   // constructor
  5.   explicit PlugInDriver(kt::PluggableServer* serv) : serv_(serv), error_(false) {}
  6.   // get the error flag
  7.   bool error() {
  8.     return error_;
  9.   }
  10.  private:
  11.   // perform service
  12.   void run(void) {
  13.     kc::Thread::sleep(0.4);
  14.     if (serv_->start()) {
  15.       if (!serv_->finish()) error_ = true;
  16.     } else {
  17.       error_ = true;
  18.     }
  19.   }
  20.   kt::PluggableServer* serv_;
  21.   bool error_;
  22. };

且只看:
explicit
 PlugInDriver(kt::PluggableServer* serv) : serv_(serv), error_(false) {}
1.
explicit  参看: http://wenku.baidu.com/view/3a02f28fcc22bcd126ff0ced.html
 
explicit 用来修饰构造函数的, 表明构造函数是显示的,而且,由explicit修饰的构造函数为默认构造函数;
  因为使用了explicit,则可以:
 
PlugInDriver p(serv);  // 而不能:
 
PlugInDriver p = serv; // 如果没有explicit ,则这样是可以的, 如:
  string s = "abcd"; // 等价于
  string s("abcd")

2. serv_(serv), error_(false)
  这个是给两个私有成员赋值,至于为什么不卸载构造函数的函数体内,参看《c++编程思想》p329

3. 基类kt::Thread 使用了public来修饰
  如果没有public来修饰的话,则子类的所有的public成员和方法在子类上都将体现为private的,这显然不是我们想看到的; 那样则可以只用组合而不用继承了

linux file命令是如何识别文件的类型的

man file、 strace file /bin/ls , 发现:

file命令参考magic文件/usr/share/file/magic.mgc, 如果/usr/share/file/magic.mgc不存在,会参考 /usr/share/file/magic ; 二者的关系为: magic.mgc 是magic 编译后的文件;编译方法为:
file -C /usr/share/file/magic.mgc -m /usr/share/file/magic

tokyocabinet 与 kyotocabinet

tokyocabinet(简称tc) 与 kyotocabinet(简称kc) 有如下主要区别:
1. tc是用c写的,kc使用c++写的
2. kc抛弃了fixedlength database, table database
3. tc只能在类unix系统中编译,kc也支持windows

Tokyo Tyrant(简称tt) 与 Kyoto Tycoon(简称kt)的区别:
1. tt是用c写的,kt使用c++写的
2. tt不支持自动过期,kt支持自动过期
3. kt有几乎tt的所有的优点
4. kt抛弃了fixedlength database, table database

参考文档: http://fallabs.com/kyotocabinet/kyotoproducts.pdf