Gemstone OODB将对JRuby及Rubinius提供支持

Gemstone是对象数据库Object DatabasesOODB)类产品的开发商,它的OODB产品中包括基于Smalltalk的Gemstone/S和基于Java的Facets。目前这家公司正在致力于为他们的产品提供Ruby支持。简而言之:JRuby将获得Facets的支持,而对于非JRuby用户则会使用Rubinius,使用一些和Gemstone/S相似的特性。

简单地说,OODB允许用户透明地持久化对象图(Object Graphs),这和关系数据库(Relational Database,RDBMS)正好相反,在关系数据库中对象数据一定是保存在数据表中的,从而引入了对象关系映射(Object Relational Mapping,ORM)的概念。ORM可以手动实现,比如说开发人员将数据储存在数据表中,也可以借助工具或者类库来完成,比如说Ruby的ActiveRecord或者Java下的Hibernate

我们采访了Gemstone的Alan McKean,借此发掘出近期与Gemstone和Ruby相关的开发工作的更多细节:

Alan解释了这些努力是如何与他们的产品范围相契合的:

GemStone拥有两个对象数据库产品:其中一个基于Java(Facets),而另一个则针对Smalltalk(GemStone/S)。我们正着眼于将Facets应用于JRuby之上,以及将GemStone/S用于Rubinius。由于JRuby项目已经发布了1.0版本,因此我们正在这个平台上进行第一次想法证实的尝试。到目前为止,一切都进展得不错。要使用Facets,必须下载我们自己的 JVM(这个JVM已经经过Sun的授权,并且我们对一些字节码进行了调整,以便对Java对象进行 透明持久化。这个JVM的速度会比目前Sun的JVM稍慢一点(在我的测试中大约慢5%左右),原因是在持久化上做了一些附加工作。

Alan目前与JRuby团队一道着手对由JRuby运行时当前实现细节所引发的一些问题进行处理:

在JRuby实现中存在着一个要去处理的问题,而我已经向JRuby团队提交了修复代码。目前JRuby并不支持序列化(或者我们的持久化方式),因为每一个Ruby对象都有对JRuby运行时的直接引用(线程、动态方法和其它内部对象)。当这些对象被序列化(或者持久化)的时候,它们会带着整个运行时系统一同序列化(持久化)。因此我发现了一种使这些对象从整个运行时系统中剥离出来的办法,并允许序列化和透明持久化。这项工作完成之后,我们整个持久化引擎就可以正常工作了。

要想体验一下到底将JRuby和Gemstone用在一起是什么样子的,我们可以看看下面的范例代码,代码中使用了持久化对象:

# to persist an object in one VM  declare a # persistent 'root' that allows access to objects with the # 'name' of the object persistent :people => :name    # begin a transaction, put a Ruby object and all objects that are  # connected to it into the persistent root, and commit it   p = Person.new('Alan') p.children << Person.new('Jimmy') p.children << Person.new('Janie') transaction   people << p commit   # in another VM  persistent :people => :name p = people['Alan'] puts p.name p.children.each do { |child| puts child.name }

Alan对API的设计进行了阐释,并解释了在Rails中如何使用这套API:

我们正在为这套透明持久化方案设计一套API。在Rails中,你不会用到“transact”和“commit”。你将只需声明持久化的根对象,然后将对象放入根对象。当请求进入时,事务边界会被创建,随后会在响应被发送之前进行事务提交。

当我们把OODB的工作方式和ActiveRecord作比之后,前者带来的好处就更加显而易见了:

因为ActiveRecord的大部分代码存在的原因是对象和关系型数据库的不匹配现象,许多ActiveRecord的代码都将变得毫无必要。例如, belongs_tohas_many等的存在都是为了提供对关联(数据库中的外键等)的支持。同样的,像 acts_as_list等,我发现很有意思的是,ActiveRecord需要许多重复的构造,违反了DRY原则。在Ruby类中声明关联并在Schema中设置外键,这一切都会消失的。

但我们确实打算支持Filters和Validations等,这些部分看起来是否还会和ActiveRecord一模一样是值得怀疑的,因为和ActiveRecord不同,Ruby对象是不需要从一个特定的类子类化的。透明持久化解决了的ActiveRecord的另外一个问题就是子类化。在关系数据库中,并不存在任何描述类层次结构的有效解决方案(可选的有稀疏数据表或者表连接)。我们的持久化方案则对这个问题提供了自然而然的支持。子类化你的核心内容,为你的领域类混入任意模块,这正好能正常工作。

接着,谈到技术细节,Alan解释了Gemstone的定制化JVM如何让持久化成为可能:

我们是对Ruby对象的Java表现形式进行持久化的。JRuby对象是一些简单的Java对象,这些对象带着实例变量的Map,它们并不基于映像。尽管我向JRuby团队提交的补丁确实允许序列化,但是我们并没有使用序列化。我们的 持久化方案基于 页缓存。在数据库提交时,会有一些小型(8K)的内存页被同步到数据库中,而因为应用程序使用的是对象引用,内存页面可能会从持久化存储中错误地换入。由于一般来说对象都会聚集在同一个内存页中,在页面被换入的时候很少会有分页动作的发生。

Ruby对象是不具备良好定义的结构的。同一个Ruby类的两个实例在结构上可能会有很大差别,之所以出现这个现象的原因是因为针对不同实例调用的方法可能会动态地给实例加入实例变量。因此一个类实例所具有的结构(和实例变量)是和它生命周期内发送给它的消息密切相关的。这和Java及Smalltalk的情况是非常不同的,在后两者中,所有的实例变量都被静态地声明在类中的固定空间内。因此,对Ruby对象的迁移并不是什么大不了的问题。当然,还是有有一些需求是有必要支持的(例如,在生成实例变量的方法被从类定义中移除的时候,同时也将这个实例变量和它相关联的值一起移除,但我们认为这是一个管理员的任务,应当由工具来支持)。

Gemstone的Ruby支持还有另外一个分支,这个分支将基于Rubinius。Rubinius是一个采用了Smalltalk VM理念并(主要)使用Ruby编写的Ruby虚拟机。(InfoQ最近发布了两篇对Rubinius项目的Evan Phoenix的采访文章:Rubinius虚拟机内幕和Rubinius对象空间和线程模型内幕剖析)。就Gemstone将如何使用Rubinius的问题,Alan做了如下解释:

顺带说一下,请多多关注Rubinius VM的开发进度。这个Ruby实现不在JRuby上运行,也用不到我们的JVM。我们正在与 Evan Phoenix一起协力,以确保这个VM能够立等可得地支持我们的需求。然后很可能你只需要安装一个gem就可以使用我们的持久化方案了。我们的初衷是为了提供一个 免费的产品(单服务器 限制4G大小的数据存储库[data repository]),我们在Seaside上就是这么做的。一旦您需要超过4G的数据或者您需要将扩展到多台服务器上,那么您 就得购买产品和相关许可了。

Gemstone一直忙于为新的Web框架和工具提供支持。紧随新的Ruby支持之后,Seaside也会得到相应支持。

我们正在将我们的持久化方案应用到Smalltalk的Seaside框架中,在今秋会发布出来。在Seaside中的方式将会和我们正在为Ruby和Rails探索的方式非常相似。

在早期的公告中这被称为GLASS,是Gemstone/Linux/Apache/Smalltalk/Seaside的缩写。

查看英文原文:Gemstone OODB to support JRuby, Rubinius

你可能感兴趣的:(Gemstone OODB将对JRuby及Rubinius提供支持)