Archive for the ‘ IT ’ Category


[zz]在Ubuntu下使用Eclipse的svn客户端报unable to load default svn client

这个不仅仅在8.04和Eclipse3.4下管用,在最新版本同样适用。

If you are running Ubuntu 8.04 and you install Eclipse 3.4 with subclipse 1.4, you will probably get the “unable to load default svn client” error when trying to add a repository.

Here it is how I solved this problem. I assume that you have the ’subversion’ and ‘libsvn-java’ packages already installed (if not, please do install them, and then follow the instructions).

1) Go to System –> Administration –> Software Sources
and under the “Updates” tab, check the hardy-backports updates. Close the window and update the package lists.
2) Run the update manager and update all packages (subversion will be updated from version 1.4 to version 1.5)
3) Edit the eclipse.ini file (it is located into the directory where you installed eclipse) by adding the following two lines, immediately after the “-vmargs” line

Code:
-Djava.library.path=/usr/share/java/
-Djava.library.path=/usr/lib/jni/

This should do the job, next time you start eclipse, it should correctly add your existing repository.

Please post comments if you have any trouble.

Cheers!

在Ubuntu上用Chrome

最近越来越鄙视FireFox同学了,在Windows上已经基本上抛弃了FF,在Ubuntu上也想如此一番,GOOGLE了一下,一个简单的教程如何在Ubuntu上安装Chrome。

sudo gedit /etc/apt/sources.list

加上以下两句:

deb http://ppa.launchpad.net/chromium-daily/ppa/ubuntu karmic main
deb-src http://ppa.launchpad.net/chromium-daily/ppa/ubuntu karmic main

然后:这句话是对我目前的版本9.10 Karmic有效

deb http://ppa.launchpad.net/chromium-daily/ppa/ubuntu karmic main
deb-src http://ppa.launchpad.net/chromium-daily/ppa/ubuntu karmic main

sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xfbef0d696de1c72ba5a835fe5a9bf3bb4e5e17b5

sudo apt-get update

sudo apt-get install chromium-browser

这样就好了。

数据库ACID中的Isolation以及各种LOCK

说实话,这方面内容和我的兴趣毫无任何关系,本人天性就讨厌这些相对而言理论化的东西,特别是在如此的复杂环境之下更是让人头疼。不过明天就要考试了,也许是我历史上的倒数第二次考试,没有办法,潜下心来啃啃这本传说中的经典书籍Jim Gray的Transaction Processing: Concepts and Techniques.

这里主要谈一谈Isolation。

在ACID中,Isolation就是里面的那个I,其实本来这个词应该有更多更好的理解方法,比如书上说从解决问题的角度来讲,可以考虑其为Concurrency Control,从技术的角度上来说,就是一个locking的机制。Isolation的本来含义是希望在有很多很多不同的线程进行调用时,确保每一个线程的执行都相当于它是一个人在单独进行,没有受到其它线程的干扰,得到其应该得到的值。

在这里,我们可以将所有对数据库的操作分为两大类型,读和写。对于读而言,它的操作仅仅只是获取值,而不会更改值,而写操作则是要更新数据的状态,带来副作用。一般而言,对于很多线程同时进行读操作,是不会产生任何问题的。但是只要其中嵌入了一个小小的写,那么一切就变得复杂起来了。不同的顺序的操作会带来很多不同的问题。我们主要将其归纳为以下三类问题:(从这个翻译可以看出中文显得有多尴尬了吧:))

1)遗失更新(Lost Update):T1读-》T2写-》T1写

对于某个操作,T1首先读取,然后根据读到的值,进行操作之后,把结果写回到这个值中去。但是在T1读完这个值后,T2对其进行了操作更新,也就是说T1这个时候的计算的依据已经不是最新的数据了,T2写的这个值就直接等于遗失掉了。举个通俗的例子,比如我给你的银行账户的值翻倍,你有100块可以变成200块。但是在我读了100以后,有个人给你打了50块,你的账户应该是150了,但是我翻倍之后直接吧200写了进去。那个50块的操作就没影了。也就是所谓的遗失更新。

2)脏读取(Dirty Read):T1写-》T2读-》T1写

脏读取更加好理解,T1对数据更新是需要一个过程的,我们假设其中有两部分。结果在第一个和第二个之间的时候,T2对数据进行了读操作。显然其读出来的值不是最新的值,是一个脏数据,这个数据是马上需要被替换掉的。还是用账户的例子,账户里本来有100块,我要给A汇出50,然后B给我打进60,所以最终我应该是110。但是由于刚汇出A,就进行了读取,结果读到的账户的值就只有50了。显然是个错误的脏的读取。

3)不可重复读(Unrepeatable Read):T1读-》T2写-》T1读

不可重读的意思不言自明就是两次读取的值不相同。T1在一次操作中需要连续读取两次数据,结果在读取之中的时候,T2进来对数据进行了更新,于是T1读取的数值就不一致了。

注意以上所有的T1和T2都是指的单一一个事务,如果是多个事务的话,就不存在这些问题了。

根据上面的这些概念,我们可以按照数据库是否能够处理以上这些问题将其分类:

一般来说分为四个级别:

级别3:所有的并行化处理都被串行化了,于是任何的以上问题都不会出现。

级别2:没有遗失更新和脏读取的问题,但是可能会存在不可重复读的问题。

级别1:没有遗失更新的问题,但是可能会存在脏读取和不可重复读的问题。

级别0:可能会出现任何一种问题,但是如果另外一个事务的级别在1或者1以上,则该事务不会去读取其脏数据。

在理清楚了Isolation的问题之后,我们来看一下Lock的问题。最常见的Lock有两种,一种是共享锁(SLOCK),一种是专有锁(XLOCK)。在持有共享锁的时候,其他的事务可以对这个数据可以读不能写,也就是说可以给它附加共享锁但是不能加上专有锁。而如果一个事务持有某个数据的专有锁,则任何其他事务都不能对这个数据附加任何锁。

在这之前,有个简单的概念可以讲一下。我们可以吧对数据库的一系列操作视为这些操作的序列:BEGIN,COMMIT,ROLLBACK.READ,WRITE,XLOCK,SLOCK,UNLOCK。对于任何一个操作序列,我们可以将其简化为只含有后面五个操作的序列:

比如BEGIN->SLOCK A->XLOCK B->READ A->WRITE B->COMMIT
我们可以吧BEGIN和COMMIT去掉,然后将COMMIT改换为所有对LOCK操作的解锁,即:
SLOCK A->XLOCK B->READ A->WRITE B->UNLOCK A->UNLOCK B

在比如BEGIN->SLOCK A->READ B->XLOCK B->WRITE B->ROLLBACK
对于所有的ROLLBACK操作,我们需要将序列中的WRITE操作再次进行,相当于滚回原状态,然后再释放锁,即:
SLOCK A->READ B->XLOCK B->WRITE B->WRITE B->UNLOCK A->UNLOCK B

但是在这些操作过程中,我们还可能会碰到另外一个问题,所谓的虚读(Phantoms)。

这个问题会发生在上锁的时候,我们对于一个学生数据库中的所有男生进一个UPDATE操作,但是这个时候又转学来了一个学生,于是无论如何上锁,这多出来的一个男生始终无法受到约束。在这种情况下,我们需要使用谓词锁(Predicate Lock)。在使用谓词锁的时候,任何插入或者删除数据的事务,只要满足这个谓词,就无法进行操作。从某个层面上,我们可以看到这个锁对数据进行了进一步的细化。

但是谓词锁也存在几个问题,最主要的一个问题就是计算量的巨大,因为每次在操作之前,都需要对所有的谓词进行比较判断。这样即严重的影响了数据库的效率。

另外一个可以解决的办法和谓词锁很相似,被称之为粒度锁(Granularity of Locks)。这个概念实际上是在谓词锁的基础之上,在操作之前,首先定义好了所有的谓词结构,将其排放成一个树状。这样任何的操作都可以很迅速地找到自己的位置。比如一个数据库,我们将其分为三层,分别是地点,文件和记录。每一层都有父子关系:

最上一层是数据库,所有的数据都属于这一层,因此这一层的PREDICATE永远是TRUE。
下面一层是地理位置,分为中国,澳洲,美国。那么分别满足这个谓词的可以在这层上是TRUE。
接下来是文件层,每一个地理位置都有不同的文件层。比如在中国有档案文件,户口文件。
然后最下面一层是记录,比如户口文件中有张三的记录,有李四的记录。

于是我们在上锁的时候,只需要按照层次进行划分即可。比如我现在需要操作的是所有的中国的档案文件,那么谓词就是地点=“中国” AND 文件=“档案”,如果我需要的是李四的户口,那么谓词就是地点=“中国” AND 文件=“户口” AND 记录=”李四”。

通过对粒度的控制,我们可以随意的掌握锁的大小来更好的调整资源。但是在这个状况下,我们又产生了一个新的问题,比如我锁定了某个儿子,但是如果其父亲要求更改其值怎么办?于是我们定义一种新的锁,称之为意向锁(Intent Lock)。当我们需要锁定一个儿子的时候,我们需要将其之上的祖先全部附加意向锁。比如我们需要给中国的户口文件附上共享锁,在这之前我们需要对整个数据库,地点=“中国”这两个谓词附加上意向锁,最后才对户口文件附加共享锁。而当一个数据被赋予意向锁之后,它不能在被附加任何的共享锁或者专有锁,当然其他的事务也可以继续对其附加意向锁。

紧接着,我们又可以看到另外一个问题。如果一个事务需要对儿子附加共享锁,而另一个事务需要对父亲附加共享锁,其实这两个操作是没有冲突的,但是因为意向锁的原因,第二个事务必须等待第一个事务操作结束才能执行。于是我们通过将意向锁继续细化的办法来解决这个问题。

意向锁被分为三类分别是:

意向专有锁(IXLOCK:可能对其儿子附加共享锁或者专有锁
意向共享锁(ISLOCK):可能对其儿子附加共享锁
共享意向专有锁(SIXLOCK):自己本身是共享锁,但是希望对儿子附加专有锁

我们同时还介绍另外一种锁,称之为更新锁(UPDATE LOCK)。更新所的目的在于避免死锁。更多的关于死锁的内容下面再讨论。

将所有的这些锁进行一个图标的总结:

None

S

X

IS

IX

SIX

S

+

+

-

+

-

-

X

+

-

-

-

-

-

IS

+

+

-

+

+

+

IX

+

-

-

+

+

-

SIX

+

-

-

+

-

-

在GAE/J上玩Web服务

Web服务是GAE的主要交流工具,其中的核心部分就是RESTlet。但是目前来说,市场上还有很多很多的Web服务是只提供SOAP服务的,比如我现在正在解决的关于调用GoGrid CDN的API,在CDN这一块,他们只提供SOAP。但是想要在GAE/J上调用SOAP简直就是不可能。因为对很多类的限制,JAX-WS等一系列的传统方式,都无法在GAE/J上运行。

有一个force.com的网站,提供了一个婉转的办法。他们提供了一个WSC的类,可以将下载下来的WSDL文件,自动生成一个JAR包其中包含所需要链接的connector和类,然后在这个类的基础之上来操纵web服务。有兴趣的同志们可以直接去看看。

但是我的问题更严重,因为GoGrid CDN的SOAP API是基于.Net的,而我是用的Java,这又是一条横岗。在GAE的Issue里已经提交了这个问题,希望Google早日支持这个库,不然的话我可不想从JAXB开始手写调用Web服务。

先暂且把这个Task放一放,Azure这个服务商提供的API是支持REST的,这样总可以解决一些问题了。

URL编码

URL中如果需要GET参数的话,有点时候会出现附加在后面的字符拥有特殊含义从而需要转义字符的时候。以下是一些简单的规范:

1)Letters (A-Z and a-z), numbers (0-9) and the characters “.”, “-”, “~” and “_” are left as is

2)  SPACE is encoded as “+”

3) All other characters are encoded as %FF hex representation with any non-ASCII characters first encoded as UTF-8 (or other specified encoding)

GAE-Java一些小的注意的地方

1. GAE的Eclipse在引用本地的library的时候,不会自动将其复制到WEB-INF/lib下去,结果就是如果选择直接上传到SERVER,程序会报找不到类的错。目前的开发人员正在改正这个问题,可能会在下一版得到解决。目前的最好解决办法,是首先将需要的类复制到WEB-INF/lib下,然后再引用。

2. 如果希望在本地调试程序的时候,可以查看datastore和queuetask的信息,可以通过http://localhost:8080/_ah/admin进入。里面提供了手动调控task的功能。

GAE-Java中JDO部分的KEY

发现有些部分的文档,看一次是绝对不可能看懂的。必须要过两天回头再来看,才发现一些端倪。比如这里要说的是JDO中类的KEY。

习惯了RDBMS开发的同志们,都会想到这还不是一个很简单的问题,无非就是选择一个唯一的可以代表该实例的作为ID就可以了。特别是目前开发中,大多数人喜欢用系统自动生成的ID序列来构造key。然而在GAE所支持的JDO中,我们会发现文档中提供了四种方式来实现KEY,不同的方法适用于不同的场合。

1. Long变量
这就是上面所说的最常见的一种,由系统自动生成的长整型变量来表示KEY。注意,这种选择只适用于那些没有父类的类。什么叫没有父类的类呢?例如有两个类,People和ContactInfo,在People类中,有一个属性就是ContantInfo,那么在这种情况下,People类就是有父类的类,而ContactInfo就是没有父类的类。

2.Unencoded String
和上面的Long变量一样,这个KEY的实现同样只适用于那些没有父类的类。但是在这里,它的值是由程序指定的,在这里使用的是没有编码的String类型。

3.Key
Key类是GAE-Java中专门提供的作为KEY的类型,它包含了可能有的父类信息以及一个系统自动分配或者程序指定的ID。也就是说,它是在包括父类信息的前提之下,选择以上两种选择之一来共同完成Key的任务。用KeyFactory的createKey()方法即可完成这一功能。

4.Key作为编码String
这种类型和Key类型是很相似的,只是将Key转化为来String来进行操作,方便使用。Key和encoded String之间可以用KeyFactory的keyToString()和stringToKey()方法互相转换。因为是String类型,所以如果想要得到ID的其中的内容,可以在声明了Key之后,附加声明其String或者Long类型的ID。@Extension(vendorName=”datanucleus”, key=”gae.pk-name或者gae.pk-id”,value=”true”)。同样,name类型的值是可以更改的,但是id类型的是自动生成无法变化的。

如何生成Key?
1. 对于没有父类的类型,我们可以使用createKey()静态方法来实现。它的参数包括createKey(String kind, String name)。其中kind就是指的要创造的类的类型,一般用Class.class.getSimpleName()来实现。第二个参数取决于使用的是自动生成的Long变量还是程序指定的String变量而定。

2,对于有父类的类型,我们同样可以使用createKey()的另一个重载方法来实现createKey(Key parent, String kind, long id)。在这里,我们首先实现父类的Key,然后将其包括在方法参数内即可。
不过在教程上,提供了另外一种方法来是实现,使用的是KeyFactory.Builder类。在这里首先通过构造函数,实现一个Key,然后不断调用addChild()方法,把子类附加上,最后通过getKey()方法得到Key。这种方法的好处在于可以产生一个链状的Builder,更加方便使用。比如在我们上面的People和ContactInfo例子之中,首先我们生成ContactInfo的Key,然后下一步附加上People的Key即可。

如何通过Key得到对象
一个很简单的方法,就是pm.getObjectById(class, key/id);如果你有的是key,第二个参数就用key;如果有的是id,第二个参数就用id。同时,你可以选择使用非类里面声明的类型,来作为第二个参数。比如在类里面使用的是Key,你可以通过调用name的String来获得。唯一的例外是String和Long之间的互相调用是不允许的。

Restlet2.0初尝试

今天一直在研究Restlet的API,大约应该是在2007年起,1.0版就已经问世了。但是由于这个概念在当时还是比较新的,所以1.0版本的普及率特别是在国内的普及率还是很低的。百度一下就会发现研究的人的确不多。现在RESTful的概念是越吵越热,且不说它到底好坏与否,但是引起这么多人的关注,就说明了它有其出色的地方。

在网站上看到的Stable的版本是1.6,于是保守地先从这个版本试起,结果发现无论如何添加Connector,都会报找不到Protocol的错,恰好这时James过来看看我,于是在他的建议之下,尝试了2.0m5版本。至少在最简单的程序部分,能够很正常的运行。

下面把一些很简单的步骤作个罗列:

在我看来,完成一个全部由Restlet构造的程序,一共需要四个部分。首先便是资源文件,对于REST概念比较熟悉的同学都应该明白,Resource在REST中是根本中的根本。于是,我们首先定义一个十分简单的Resource,为了简单起见,我们只给它附加两个功能,GET和POST。其中GET方法,很简单的返回一个String,POST方法是将得到的两个数进行相加返回结果字符串。

public class TestResource extends ServerResource{

	@Get
	public String getResultGet(){
		return "This is my test!";
	}

	@Post
	public String getResultPost(Representation entity){
		Form form = new Form(entity);
		String first = form.getFirstValue("first");
		String second = form.getFirstValue("second");
		int a = Integer.parseInt(first);
		int b = Integer.parseInt(second);

		return "The result of "+a+"+"+b+"is "+(a+b);
	}
}

在这一步结束之后,我们需要把资源放到一给应用(Application)中去,同时要提供访问它的路径。我个人心目中就把这个部分成为RouterPath,因为这两个单词也是这个文件中最多见的。

public class RouterPath extends Application{
        @Override
	public Restlet createInboundRoot() {
		// TODO Auto-generated method stub
		Router router = new Router(getContext());

		router.attach("/greeting",TestResource.class);

		return router;
	}
}

在这一给类中,它继承来Application这个类,目的就可以看成是提供了一个程序环境,在这个大的环境之下,你输入的方法,就将被引导到某个类之中去。比如在这里,所有的以greeting结尾的请求,都会被引导到我们刚才所创建的类里面去。

有来这样两样以后,我们只需要启动这个资源让它开始服务就可以了。我把这个类命名为StartResource类。

public class StartResource {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		try {
			// Create a new Component.
			Component component = new Component();  

			// Add a new HTTP server listening on port 8182.
			component.getServers().add(Protocol.HTTP, 8182);  

			// Attach the sample application.
			component.getDefaultHost().attach(new RouterPath());  

			// Start the component.
			component.start();
		}catch (Exception e) {
			// Something is wrong.
			e.printStackTrace();
		}
	}
}

我们可以很清楚的看到,这个类启动来在端口8182上的HTTP协议,然后将前面的Application附加在来这个端口上。然后服务就开始启动,等待他人的使用了。

现在我们就可以直接在浏览器中输入这个URL,来调用GET方法了。在这里,我们输入http://localhost:8182/greeting,屏幕上就出现来This is my test!字样。当然浏览器是不支持POST,PUT和DELETE直接在地址栏中的,我们可以用一个简单的JSP界面做一给POST框体,也可以像如下的类用Restlet提供的Client来完成请求。

public class Client {
	public static void main(String[] args) {
		int a=4;
		int b=9;
		ClientResource client = new ClientResource("http://localhost:8182/greeting");
		try {
			System.out.println(client.get().getText());
			Form form = new Form();
			form.add("first", a+"");
			form.add("second",b+"");
			System.out.println(client.post(form.getWebRepresentation()).getText());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

很容易看到,GET方法是可以直接用client得到的,而POST方法需要传入一个参数,也就是Resource端所需要的参数。用类似的办法,我们同样可以完成PUT和DELETE。

以上的这个例子实际上非常基础,但是至少展现来Restlet的一些特点,首先它是一个很完善的既支持客户端又支持服务端的API;其次它的结构也十分清晰,只要很好的划分了不同的请求,就能很好地看清楚之间的逻辑;最后就是API的封装还是很简洁的,尤其是在客户端调用这一块。

明天开始继续深入研究,更多的Tutorial可以参见http://www.restlet.org/documentation/2.0/tutorial

几个在GAE的datastore方面不太理解的问题

乍一看上去,觉得GAE的确是给很好的东西,理念十分先进,虽然datastore看上去和关系数据库很相似,但实际在底层的设计上却是有着决然的不同。今天看来一天,发现来几个问题还是无法理解的,先mark出,以免忘记。

1. datastore的数据是不是永远存在的,也就是说google会不会主动去删除。问题一在,如果数据越增越多,会不会影响效率,当然在小范围内我们可以预见到是没有问题的,可过给十年八年呢?问题二,是不是每建一给数据类型,就会有一个对应的Entity类型出现,那也就是说如果我把以前的数据类型的某一项属性稍微更改一下,那么这个旧数据就相当于垃圾一样存在来datastore中?

2. Key这个玩意,感觉上和主键很相像,但是却有很多不同之处。比如GAE规定,Key只能有四种形式,Long, Unencoded String, Key和Key as Encoded String。对于这之间的区别实在是十分模糊。比如在关系数据库中,我们常用的是设立一个自增的主键,而在这边呢,到底是用哪一种呢?而且Key的String值还是自动随机生成的。

3. 数据在google那边到底是如何存储的,是杂乱无章的,还是按照某种顺序?也许就是直接按照Hash来进行存储的,但在获取的时候,如何才能提高效率呢?特别是当数据量非常之大的时候?

思考一下,有结果了再来继续。

另外加些

1. GAE的一些本地内容是存储在\war\WEB-INF\appengine-generated下面的,有两个。分别是datastore-indexes-auto.xml负责存储index信息,和 local-db.bin存储的是本地的数据。

算法–日期函数

问题:给定了年份和第几天,返回月份和日期。如输入2004年第61天,返回3月1日。
在Elements of Programming Style中,作者给出了最简单的算法只需要5行代码外加一个26个整数的一维数组。

Older Entries Newer Entries
  • English Version

    • Cannot read Chinese? Please take a look at my English site, hope you can find more you need there!
  • 感谢支持

  • twitter

    facebook

    linkedin

    • You are currently browsing the archives for the IT category.

  • Categories