相对于传统的编程语言来说,javascript一直显得不那么直观,尤其是它的Scope、this、对象模型等,无论我看过多少次,长时间不接触就容易遗忘。因此也希望在写此文时能深刻的理解并记住。

function Person(name) {
  this.name = name;
}
Person.prototype.sayHello = function() {
  alert("Hello, I'm " + this.name);
};
var p = new Person('Aaron');

上面一段代码:

  1. 声明了一个Person类型
  2. Person类型一个变量为name
  3. Person类型有一个方法为sayHello
  4. 创建了一个Person的全局对象p,参数name为’Aaron’

疑问:

  1. this是代表什么?
  2. Person明明是一个函数,为什么是类型?
  3. Person.prototype是什么?
  4. 如何给Person声明私有变量或方法?
  5. 如何去实现继承?
其实这段代码背面代表了很多javascript的核心知识,我从简到难试着说明一番:

捉摸不定的this

在其他语言中,this就是执行当前方法所使用的对象。其实javascript也差不多,

但是在混乱不清的调用后,我们往往搞不懂this的指向。其实两句话就可以说清:

  1. 在函数外部,this就是window对象
  2. 在函数内部,this就是函数的拥有者

第2点也决定了this是不会产生嵌套传递的。这个有个例子:

var name = 'window';
function A() {
alert(this.name);
}

var boy = {name: 'boy'};
boy.B = function() {
   alert(this.name);
}

var girl = {name: 'girl'};
girl.C = boy.B;
girl.D = A;
//输出
alert(this.name);//window
A();             //window
boy.B();         //boy
girl.C();        //girl
girl.D();        //girl
  1. 全局定义的函数相当于window对象的方式,即window.A = function() {…}; 因此该函数里this就是window
  2. 当把一个函数显示的赋值给一个对象的属性时,无论该函数是在哪定义的,都相当该变量拥有了该函数,例如boy.B,girl.C,girl.D

对象就是个词典

首先,回顾一下程序设计中的“对象”是什么?简单的说就是包含一组数据和方法的“数据”。
javascript一切皆“对象”,其实也就是个类似“词典”的东西,它的key就是它的变量名和方法名。因此你也可以像这个来创建对象:
var obj = {};
obj.__class__ = 'Person';
obj.name = 'Aaron';
obj.method = function (xxx) {...};
但是像上面那样去创建会显得很麻烦,所以可以把这几行代码定义一个函数,以达到复用的目的:
function SomeClass(name) {
  ...
  return obj;
}
我记得曾经有些流行的第三方就是用这样的方式来定义“类”和产生对象的。

对象不只是个词典

javascript对象有一个很特殊的属性:[[Prototype]],在Firefox和Chrome中是__proto__,javascript用它来实现继承的机制。当我们访问obj.name时:
  1. 如果obj里定义了name,如obj.name = ‘xxx’,则返回它。
  2. 如果未定义,则查找obj.__proto__中有没有定义name。
  3. 如果未定义,则查找obj.__proto__.__proto__,以此类推,直到Object.__proto__(为空)
javascript在具体的使用时,又引入了名为prototype属性,当然,其实叫什么名字都可以,但是这个名字很容易和[[Prototype]]混在一起。它们的实质并不同。
定义一个函数,如:function A() {}时,相当于:
A = function() {...};
A.prototype = {};
A.prototype.__proto__ = Object.prototype;
A.prototype.constructor = A;
创建一个对象时,var a = new A()时,相当于:
var a = {};
a.__proto__ = A.prototype;
a.constructor();//实际指向了A.prototype.constructor
当要给类定义方法时,那么就有两种方式:
  1. this.method = function() {…}
  2. A.prototype.method = function() {…}
这两种方式的不同在于,第2种方式,有可能在后续运行中改变已创建的A对象的方法。(想想为什么是有可能?)
那么对于继承,比如有个类B,要继承A,可以通过如下方式:
B.prototype = new A();
B.prototype.constructor = B; //因为上一行把constructor更改了
如果A类型都用this.xxx = xxx来定义变更和方法的话,还可以:
function B() {
  A.apply(this, arguments);
...
}
如果都没有用this.xxx=xxx的话,可以直接prototype继承:
var TEMP = function(){};//需要用一个空对象过滤一下,不然会有问题
TEMP.prototype = A.prototype;
B.prototype = new TEMP();
B.prototype.constructor = B;
其他还可以直接对prototype遍历赋值等方式。下面描述了Javascript的对象模型:
javascript_object_layout

函数是与众不同的对象

权威指南里有个话很重要:
“JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里.”
这是为什么呢?因为函数有一个[[Scope]]属性。
  1. 一个函数在创建的时候,会把当前执行环境的Scope Chain传给Function的[[Construct]]方法,[[Construct]]创建一个内容与传入的Scope Chain完全一样的新的Scope Chain,,并赋给被创建函数的内部[[Scope]]属性。
  2. 在函数被调用时会创建一个新的Scope Chain,和函数的[[Scope]]内容一样,然后又创建一个[[Activation Object]],包含了该函数的所有参数(包括arguments)和局部变量的定义,并插入到Scope Chain的最前端。
参考:
http://www.cnblogs.com/RicCC/archive/2008/02/15/JavaScript-Object-Model-Execution-Model.html
http://www.laruence.com/2010/05/13/1462.html
 

在配置的过程中,遇到不少问题,文档上很多东西也说得不清不楚,经过很多尝试才成功。以2.6.1版本为例。

1. 配置没有生效
在rabbitmq.config中,shovel的配置一定是以’rabbitmq_shovel”,网上有些sample是’rabbit_shovel’,虽然rabbitmq成功启动了,但是shovel却没有任务反应。

2. 提示badmatch, {error, auth_failure}
我配置的从远程一台broker把消息抓到本地,本地的broker写成”amqp://”,文档上说这种情况下,是直接从内部传输,应该是不需要验证。结果最终还是写成”amqp://user:passwd@localhost/”才成功的。

3. 配置解析失败
要注意sources/destinations中,broker和brokers是有区别的,后者的参数是list格式,即[]。

可以通过rabbitmq_shovel_management插件查看状态,比较直观

 

由于项目的数据存储主要使用的Cassandra,但发现它的读性能实在不怎么样,不过发现0.7之后可以解决之前的很多问题。

参考:
• http://www.rackspacecloud.com/blog/2010/10/27/new-features-in-cassandra-0-7/
• http://svn.apache.org/repos/asf/cassandra/branches/cassandra-0.7/CHANGES.txt
• http://wiki.apache.org/cassandra/API

1. 二级索引,对于SuperColumn中的Column支持索引,这个很重要,因为用的太多了,对SuperColumn对range读取,会把带个SuperColumn先读取出来。。

2. row大小支持2billion个column,之前是2GB。
3. Keyspace和ColumnFamily的定义可以动态更新
4. 加入了网络结构因素的一致性策略,ConsistencyLevel.DCQUORUM,DCQUORUMSYNC.
5. 可选的per-column存活时间,这样就不用手工去删除过期数据。我一直还为怎么删除过期数据头痛。。
6. 支持truncate,可以直接删除一整个ColumnFamily
7. Hadoop某些方面的支持
8. 读取速度提升8倍。Very Important!
9. ByteOrderedPartitioner,根据Key字节流的顺序
10. 在Keyspace间的Round-robin调度,这个不太明白。
11. Dynamic endpoint snitch,似乎是可以减轻节点数据分布不均的影响
12. 新的IntegerType类型,比LongType要快
13. 细粒度的验证系统
14. 旧的数据文件仍然兼容

官方介绍的升级方式,决定一试,不过虽然旧的数据仍然可以使用,我还是决定重新import一遍。
1. Thrift API与之前的不再兼容,可以选择High-level的client
2. 节点内部的通信协议不再兼容,因此不能与之前的版本的节点混合
3. Keyspace和ColumnFamily定义在system keyspace中
4. 过程
a. 在每个0.6节点上运行:nodetool drain,然后停止节点
b. 用config-converter转换配置文件
c. 更改任务不符合^\w+正则的Keyspace名称
d. 启动0.7的Cassandra
e. 使用schematool导入Keyspace定义,只需要在一个节点上执行

 


1. 增加高亮显示


通过重载_renderItem函数,并替换匹配字符串xxx为xxx
使用的时候把autocomplete替换为highlightcomplete即可,请参考官方指南

显示效果

$.widget("aaron.highlightcomplete", $.ui.autocomplete, {
    _highlight: function(label) {
        var matcher = new RegExp("("+$.ui.autocomplete.escapeRegex(this.term)+")", "ig" );
        return label.replace(matcher, "$1");
    },
    _renderItem : function( ul, item ) {
        return $( "
  • " ) .data( "item.autocomplete", item ) .append( "" + this._highlight(item.label) + "" ) .appendTo( ul ); } });


    2. 增加分组显示


    其余与官方的例子一样,需要配合CSS。可以重载category函数以显示分组。

    显示效果:

    以下是代码:

    /**** 分组的css显示 ****/
    .ui-autocomplete-category {
            font-weight:bold;
            background-color: #CCC;
            color: white;
            padding: .2em .2em;
            line-height: 1.5;
    }
    
    //这里直接继承了highlightcomplete,这样可以同时高亮和分组
    $.widget("aaron.catcomplete", $.aaron.highlightcomplete, {
        _renderMenu: function( ul, items ) {
            var self = this,
            currentCategory = "";
            var li = "
    
  • "; if (self.options.category) { var map = self.options.category; } else { var map = self._category; } $.each( items, function( index, item ) { var category = map(item); if ( category != currentCategory ) { ul.append( $(li).html(category) ); currentCategory = category; } self._renderItem( ul, item ); }); }, _category: function(item) { return item.category; } }); //使用方式,可以重载category函数来以特定的方式显示 $("#search").catcomplete({ source: "/suggest.php", category: function(item) { return item.category; }, minLength: 1 });
     

    vserver的安装非常简单,其原理也比较简单,相当于一个加强版的chroot,有自己的虚拟设备。
    由于它是共享内核的,只是运行在不同的context下,所以效率损失非常少。

    1. 安装vserver内核
    需要注意选择合适的内核版本,比如32位还是64位等。debian下只需要执行

    #安装image, util工具
    aptitude -r install linux-image-2.6-vserver-686-bigmem util-vserver
    #更新grub启动,默认进入vserver内核
    update-grub
    #重启
    reboot
    #通过uname查看内核版本,可以看到vserver
    aaron:~$ uname -a
    Linux aaron 2.6.26-2-vserver-686-bigmem #1 SMP Thu Aug 19 07:38:48 UTC 2010 i686 GNU/Linux
    

    2. 创建一个vserver
    这个会创建一个名称为test, IP为10.10.10.10的vserver,安装方式是debootstrap,
    rootdir指定了文件创建的位置,interface用于指定网卡和IP。

    NAME='test'
    IP='10.10.10.10'
    ROOT=/home/vservers
    vserver $NAMEbuild -m debootstrap \
    		--hostname $NAME\
    		--force \
    		--rootdir $ROOT \
    		--interface eth1:$IP/24 \
    		--interface lo:127.0.0.1/8 \
    		-- \
    		-d lenny -m http://mirrors.163.com/debian
    

    执行时会发现以下事情:
    1. 在/home/vservers目录中建立了test目录
    2. 从mirror中下载系统中必要的安装包并安装到test下(可以指定安装另外的安装包)
    3. 建立了eth1这块网卡,绑定到了10.10.10.10,在物理机中可以通过ip addr查看到。
    安装完之后,进入/home/vservers/test目录,你可以看到下面的文件目录结构和/是一样的。

    3. 启动vserver

    #启动
    vserver test start
    #进入
    vserver test enter
    

    进入后可以发现和物理机器没有明显的区别。你可以在里面创建用户、安装deb包。

    4. 其他设置
    1. 由于chroot的环境中,还是有不少方式可以jailbreak,所有需要给vserver的目录设置barrier flag

    #给vserver的root目录设置barrier,在物理机中执行。
    setattr --barrier /home/vservers
    #取消barrier设置
    setattr --~barrier /home/vservers
    

    2. 设置ssh
    虽然10.10.10.10被绑到了vserver上,但是由于物理机监听的是0.0.0.0,因此ssh 10.10.10.10时
    会直接登录到物理机中,需要更改/etc/ssh/sshd_config中的ListenAddress,只监控自己的IP。

    3. vserver配置
    vserver的网卡、fstab必须在物理机中配置
    a. 网卡:/etc/vservers/test/interfaces,0、1代表是第几块网卡,dev是设备名,ip文件中包括IP地址
    b. fstab:/etc/vservers/test/fstab,可以在该文件中mount物理机中的目录(通过bind方式)

    5. 常用命令(物理机中执行)
    1. vserver:vserver的管理工具,可以通过vserver –help查看帮助
    2. vps:相当于ps,但是可以查看到vserver中的进程
    3. vserver-stat:查看vserver状态
    4. vserver-info:查看vserver安装情况

     

    英文原文:http://virt.kernelnewbies.org/Linux-VServer

    Linux-Vserver通过内核级别隔离的方式 ,为GNU/Linux系统提供虚拟化支持。可以同时运行多个虚拟单元 ,这个单元被完全的隔离来保证安全,同时由于它们运行在同一个内核中,因此可以有效的利用资源。

    The Linux-VServer approach
    摘要

    Linux-Vserver技术是一个基于安全上下文的软分区的概念,它支持在单个物理服务器上创建多个独立的虚拟私有服务器(VPS),并能有效的共享硬件资源。

    一个VPS和一台常规的Linux服务器非常相似。所有服务,比如ssh, mail, web和database服务进程可以直接在VPS中启动和运行,并不需要任何改动。

    每一个VPS有自己的用户数据和root密码,和其他VPS完全独立,它们只是共享相同的硬件资源。

    介绍
    经过多年的发展,计算机的能力已经足够虚拟出多个小型的虚拟机器(VM),每个虚拟机器上运行一个独立的操作系统。

    目前有很多类型的虚拟机器(VM)支持相似的功能特性,但是在抽象的级别和虚拟的方式上有所不同。大部分通过模拟硬件设备,再将请求转到宿主机器上的真实资源(宿主机器上运行这些VM)。大部分系统仿真都使用这种方式(像QEMU或Bochs),支持运行客户操作系统(Guest OS),甚至仿真不同的体系架构(CPU和硬件)。由于客户操作系统(Guest OS)不知道它并没有运行在真实的机器上,因此不需要修改它。

    一些系统仿真(包括泛虚拟化)需要对宿主(或客户)系统进行少量的修改和添加特殊的驱动程序,以提高性能并减少硬件仿真中的消耗。虽然这种方式可以明显的改进性能,但在客户和宿主之间的Cache和调用仍然存在大量的浪费(比如User Mode Linux和Xen)。

    但如果当你不需要在一个单独的盒子中运行多个不同的操作系统呢?大部分的应用程序不需要访问硬件或内核级别的代码,因此在被隔离和保护的情况下,可以很容易的和其他共享一台机器。

    概念
    在一个基本的级别,一台Linux服务器由三个部分组成:硬件,内核和程序。硬件通常依赖于提供商和系统维护人员,因为它对整体性能有较大的影响,无法被轻易的更改,而且在不同的服务器安装硬件配制也不一样。

    内核的主要目的是作为硬件的抽象层,让程序可以使用和操作资源(数据),而不需要知道硬件操作的细节。在理解情况下,使用解释编程语言来编写程序时,不需要硬件相关的知识,因此可以和硬件完全没有关联。

    如果一个系统拥有的足够资源可以运行十倍于一台服务器程序数量呢?为何不在这个上面运行十个“服务器”,并让它们充分的共享资源呢?

    大部分的服务进程(如httpd)假设它是唯一一个提供特定服务的程序,部署在特定的文件目录结构和环境中。如果相同的服务运行在同一物理机器上但使用不同的网络地址,则必须做一定的调整。这导致大量的系统管理工作,并降低了稳定性和安全性。

    Linux-VServer方案的基本概念就是分离用户空间环境,成为不同的单元(即VPS),每一个VPS就如同一台运行着各类进程的真实服务器。

    虽然不同的Linux发行版使用内核补丁来提供特殊的硬件支持和功能,但是大多数的发行版并没有直接绑定特定的Linux内核。

    Linux-VServer就是利用这样的特点,在一个单独的、共享的内核运行多个VPS,因此VPS不需要直接访问硬件,同时可以有效的共享资源。

    如此,你应该已经知道linux-vserver使用的是操作系统级别的虚拟化。

    隔离 VS 虚拟(Isolation vs. Virtualization)
    由于性能原因,有些组件不能完全的虚拟化,但是可以利用隔离来保证单元间互不干扰。
    隔离:
    • 用户/进程 空间
    • 网络空间
    • IPC(进程间通信)/UTS(UNIX Timesharing System,包含了运行内核的名称、版本、底层体系结构类型等信息)空间
    虚拟:
    • 用户空间信息和可见性
    • 硬盘空间和内存
    • Init pid
    特性:
    • 文件系统标签(persistent filesystem tagging),用于设置VPS的磁盘使用限制
    • 写时复制链接(copy on write (CoW) link breaking)
    • 网络/模板(network/template based guest creation)
    • 资源使用限制/系统可扩展性(resource limits and extensive capability system)
    • 细粒度/粗粒度高效调度(fair/hard scheduler with minimal overhead)

    支持硬件:
    所有Linux体系都支持,但是并没有对所有体系进行充分的测试(主要是缺少硬件),如下是已知可以运行的体系:
    • alpha
    • i386 and higher (and compatible)
    • ia32 / ia64
    • mips / mips64
    • hppa / hppa64
    • ppc / ppc64
    • sparc / sparc64
    • s390 / s390x
    • x86_64 (AMD64)
    • uml/xen

    发行版
    • linux-vserver与发行版无关,可以所有的宿主/客户组合都支持,不过,一些客户发行版有着更好的支持。

     

    最近的项目对第三方开源软件(主要是PHP)进行扩展,涉及到了web和数据处理,php用来做数据处理真是不合适。于是引入Python,但就得解决PHP和Python的通信问题。调查了RabbitMQ,  ZeroMQ,  ActiveMQ。一开始本打算用号称高性能的ZeroMQ,但发现文档不全,API极不稳定。最终还是回到RabbitMQ。这里写一个php通过RabbitMQ调用Python方法。

    Message Queue: RabbitMQ, http://www.rabbitmq.com/
    PHP Client:http://pecl.php.net/package/amqp
    Python Client: http://code.google.com/p/py-amqplib

    Python实现了一个AMQPServer,接口参数了Python标准库里的SimpleXMLRPCServer。

    #!/usr/bin/env python # encoding: utf-8
    
    try:
            import json
    except ImportError, e:
            import simplejson as json
    from amqplib import client_0_8 as amqp
    import os, traceback
    from Queue import Queue
    import thread
    
    class AMQPServer:
            def __init__(self, host='127.0.0.1:5672', userid="guest", passwd='guest',
                    vhost='/', insist=False, max_thread=3):
                    self.__conn = amqp.Connection(host=host, userid=userid,
                             password=passwd, virtual_host=vhost, insist=insist)
                    self.__chan = self.__conn.channel()
                    self.__tokens = Queue(max_thread)
                    self.__func_dict = dict()
    
            def queue(self, name, durable=True, exclusive=False, auto_delete=False):
                    self.qname = name
                    self.__chan.queue_declare(queue=name, durable=durable,
                             exclusive=exclusive, auto_delete=auto_delete)
    
            def exchange(self, name, type='direct', durable=True, auto_delete=False):
                    self.ex_name = name
                    self.__chan.exchange_declare(exchange=name, type=type,
                            durable=durable, auto_delete=auto_delete)
    
            def bind(self, routing_key):
                    self.__chan.queue_bind(queue=self.qname, exchange=self.ex_name,
                            routing_key=routing_key)
    
            def register_function(self, func, func_name):
                    self.__func_dict[func_name] = func
    
            def __callback(self, message):
                    print "__callback: %s" % message.body
                    data = json.loads(message.body)
                    func_name = data['method']
                    func_params = data['params']
                    func = self.__func_dict.get(func_name, None)
                    if not func:
                            return
                    try:
                            func(**func_params)
                    except Exception, ex:
                            print traceback.format_exc()
                    finally:
                            self.__tokens.get(True)
    
            def __handle(self, message):
                    self.__tokens.put(message, True)
                    thread.start_new_thread(self.__callback, (message,))
    
            def serve_async(self, *args, **kwargs):
                    thread.start_new_thread(self.serve_forever, args, kwargs)
    
            def serve_forever(self, exchange=None, queue=None, routing_key=None):
                    if exchange:
                            self.exchange(exchange)
                    if queue:
                            self.queue(queue)
                    if routing_key:
                            self.bind(routing_key)
                    self.__chan.basic_consume(queue=self.qname, no_ack=True,
                            callback=self.__handle, consumer_tag="consumer")
                    while True:
                            try:
                                    self.__chan.wait()
                            except Exception, ex:
                                    print traceback.format_exc()
                                    break
    
            def close(self):
                    self.__chan.close()
                    self.__conn.close()
    
    def test(msg):
            print "Thread %s Recevied %s:" % (thread.get_ident(), msg)
            import time
            time.sleep(10)
            print "Thread %s Finished %s:" % (thread.get_ident(), msg)
    
    if __name__ == '__main__':
            MQ_EXCHANGE = 'amq.direct'
            MQ_QUEUE = 'rpc'
            MQ_ROUTING_KEY = 'rpc'
            mq_server = AMQPServer()
            mq_server.register_function(test, 'test')
            try:
                    mq_server.serve_forever(MQ_EXCHANGE, MQ_QUEUE, MQ_ROUTING_KEY)
                    #mq_server.serve_async(MQ_EXCHANGE, MQ_QUEUE, MQ_ROUTING_KEY)
            except KeyboardInterrupt:
                    os.kill(os.getpid(), 9)
            finally:
                    mq_server.close()
    

    PHP,一个类似RPC的函数

    
    function amqp_call($method, $params, $exchange='amq.direct', $queue='rpc') {
        $cnn = new AMQPConnection();
        $ex = new AMQPExchange($cnn, $exchange);
        $message = array(
            'method' => $method,
            'params' => $params,
        );
        $ex->publish(json_encode($message), $queue);
    }
    
    amqp_call('test', array('msg'=>'Hello Rabbit'));
    
     

    N年前写的。。。

    #include 
    #include 
    #define MAXN 100000
    using namespace std;
    int main()
    {
            char str[MAXN];
            int next[MAXN];
            int maxpos = 0;
            int maxlen = 0; 
    
            cin >> str;
            int len = strlen(str);  
    
            for (char *s = str; s[0] != '\0' && len > maxlen; s++, len--) {
                    next[0] = -1;
                    for (int i = 1, j = 0; i < len; i++, j++) {
                            while (j >= 0 && s[i] != s[j]) j = next[j];
                            next[i] = j;
                            if (j > maxlen) {
                                    maxpos = i + s - str - j;
                                    maxlen = j;
                            }
                    }
            }
            cout << "result : " << maxpos << ' ' << maxlen  + 1 << endl;
    }
    
    © 2011 AIQ Suffusion theme by Sayontan Sinha