Domino 8.5 版引入了新的设计元素:xPage。我承认这是个很强大的东西,但在很多生产服务器我们还没有用到它。而我向来有关闭这种不使用的功能的洁癖,所以通过以下参数可以将其禁用:

INOTESDISABLEXPAGECMD=1

设置参数后重启 HTTP 服务即可生效。

在开发过程中我们经常使用 msgbox 语句来调试代理,由于种种原因有时这些调试语句会被带入测试/生产环境。这种问题一旦发生,一般来说很难定位它究竟来自哪个代理。

此时我们可以在 notes.ini 中添加

Debug_Agent_Thread=1

参数来打开 Web 代理调试功能,在代理开始和结束时,控制台会打印出代理的名称、所在数据库以及 thread id。有了这些信息,我们就很容易定位调试语句的来源了。

请参考:Lotus Notes.ini Entry – Debug_Agent_Thread

前些天在讨论 Domino 环境中各种 ID 时,提到了一些关于如何处理复制冲突的内容,由于其原理比较复杂,当时就没有展开讨论。今天有读者询问其中的细节,所以在这篇文章中我们就仔细研究一下这个话题。

上一次说到在复制过程中如果发现两个副本关系的文档其 OID 不同,那么说明这两个文档处于不同步的状态。首先分析两个文档的 $Revisions 域(此域记录了文档历次修改的时间),判断是否存在冲突:

  • 如果两个域值除了某一个文档多出来一些值以外,其余部分完全相同,如:

    A:时间1,时间2,时间3
    B:时间1,时间2,时间3,时间4,时间5

    则表示 B 文档在 A 文档的基础上额外多修改了两次,不存在冲突

  • 如果两个域值最初相同,然后各自出现了不同的部分,如:

    A:时间1,时间2,时间3,时间4
    B:时间1,时间2,时间3,时间5

    则表示两个文档在不同的时间分别修改过,存在冲突

如果存在冲突,下一步检查目标文档(就是这次复制过程中会被修改的那个)的 $ConflictAction 域,如果其值为“1”表示允许合并复制冲突,开始分析两个文档各个域值,以判断能否进行合并:

  • 首先通过 $Revisions 域和 Sequence Number 找出两个文档最后一致的版本,以下面数据为例:

    A $Revisions:时间1,时间2,时间3,时间4
    A SN:5
    B $Revisions:时间1,时间2,时间3,时间5
    B SN:5

    两个文档在时间3这一版本是一致的,从 SN = 5 往回反推可以得到一致版本为 4

  • 每个文档域也有一个 SN 属性,它记录了此域最后一次修改时文档的 SN。用文档域的 SN 与之前得到的一致版本号 4 进行比对,就可以得到在一致版本之后修改的域。
  • 如果两个文档修改过的域有重合的部分,说明在不同的副本中对相同的域同时做了修改,无法合并冲突;反之则可以合并

如果 $ConflictAction 域值不是“1”或者属于上一段所述无法合并冲突的情况,则必须创建冲突文档。下一步就是通过 Sequence Number 和 Sequence Datetime 来分析哪个文档作为主文档(winner),哪个文档作为冲突文档(loser):

  • SN 比较大的(在一致版本之后编辑次数较多的)文档是 winner
  • 如果 SN 相同,SD 比较大的(最后编辑的)文档是 winner

至此,一个崭新的复制冲突文档诞生了。

本文主要记录我在 Mantis 配置过程中遇到的几个问题,其安装比较简单这里就不详细描述,只是要注意 Mysql 安装时字符集选择 UTF-8。

(注:我的软件环境: Windows 2003,PHP 5.2.13,Mysql 5.1.46,Apache 2.2.15,Mantis 1.2.1)

  • 更改默认时区:在 config_inc.php 中加入
putenv("TZ=Asia/Shanghai");
  • 更改默认语言:在 config_inc.php 中加入
$g_default_language='chinese_simplified';
  • 更改窗口/页面标题:在 config_inc.php 中加入
$g_window_title = 'Bug跟踪系统';
$g_page_title = 'Bug跟踪系统';

之后发现标题变为空白,将 config_inc.php 改为 UTF-8无BOM格式 后问题解决。

  • 图表中文乱码问题

由于 Mantis 自带的图表引擎效果不好,所以建议使用 JpGraph 引擎。首先下载 JpGraph,将压缩包中 src 目录下所有文件解压到 {mantisroot}/library/jpgraph

以管理员帐号登录系统,通过 管理>插件管理 安装 Mantis图表 插件,然后对其进行配置:将第一项图表引擎改为 JpGraph,其余保持默认设置并保存(尤其是字体要保留 Arial,下面会用到)。至此图表已经可用,但中文乱码。

由于我的 Mysql 字符编码为 UTF-8,所以无需像网上大多数文章所述进行转码,直接找一个含有中文字符的字体即可。编辑 {mantisroot}libraryjpgraphjpgraph_ttf.inc.php 文件,通过查找 “FF_ARIAL =>”找到 Arial 字体配置部分,将原来的 arial.ttf 及各种粗斜变体替换为任意中文字体,样例如下:

FF_ARIAL =>   array(FS_NORMAL =>'msyh.ttf',
 FS_BOLD  =>'msyhbd.ttf',
 FS_ITALIC =>'msyh.ttf',
 FS_BOLDITALIC =>'msyhbd.ttf' ) ,

编辑好保存文件,乱码搞定。

在 Domino 应用开发中,有很多方法可以对数据进行查询。@dblookup 和 NotesView.getAllDocumentsByKey 利用了预先建好的视图索引,所以在各种查询数据的方法中,它们的性能是最出色的,也是我们最常用的。

最近在工作中遇到了一个于此相关的问题,请大家也注意:如果查询的视图具有多层分类,那么 @dblookup 和 getAllDocumentsByKey 只能返回第一个子分类下的结果。以如下数据为例:

分类1
  分类1.1
    文档1.1.1
  分类2.2
    文档1.1.2
分类2

如果以“分类1”作为查询条件,则只有“文档1.1.1”会返回,同样符合条件的“文档1.1.2”则丢失。

请参考:Troubleshooting @DbLookup, @DbColumn, GetAllDocumentsByKey

今天同事报告一个问题:Linux 平台下的 Domino 服务器运行一段时间之后,Notes 客户机无法连接,但 HTTP 服务器却是好的。同时在服务器控制台上出现以下错误:

WARNING: the maximum number of file handles (ulimit -n) allowed for Domino is 1024. See Release Notes and set the allowable maximum to 20000.

经查明其原因是在 Linux 默认设置下,每个进程能够使用的 file handles 为 1024,达到这个限制之后就无法再打开任何文件了。修改此设定分为两种情况:

  • 用户登录系统手工启动 Domino(修改 /etc/security/limits.conf 文件)
  • 通过 /etc/init.d 脚本自动启动(在启动脚本中增加 ulimit -n 20000 命令)

具体方法请参考 IBM 技术支持文档

大概在很早之前,我就知道在域中一个中文字符占三个字节,但是不知道其中的细节。最近在处理一个关于域内容超限的问题的时候,研究了一下字符编码,终于明白其中的原因。

在 Domino 环境下开发时,我们接触的字符编码主要有三种:

  • UTF-16:LotusScript 内部的字符编码,中文和英文都占两字节。
  • LMBCS(Lotus Multibyte Character Set):存到文档域中的值以及公式等使用,中文占三字节,英文占一字节。这是在 Unicode 标准推出之前,Lotus 为了解决多语言问题自己使用的编码方式。
  • 操作系统的编码方式:我们的 Domino 一般都跑在 GB2312 环境下,中文占两字节,英文占一字节。

UTF-16 和 GB2312 就不多说了,网上介绍的文章非常多。这里着重说明一下 LMBCS。

LMBCS 为了解决多语言问题,将字符分成了若干个组并将其分别编号,从 0x01 到 0x1F,其中 0x01 为 Latin-1(每个文字一字节),0x13 为简体中文(每个文字两字节)。然后每个字符都以自己的组编号开头,这样就实现了在一个字符串里面包含多种语言。例如“中文Test”以如下几个字节表示:

13 d6 d0 13 ce c4 01 74 01 65 01 73 01 74

其中加粗的部分为组编号。很明显这种访问有个很大的问题:每个字符都要标识其组编号,大大的浪费了空间。所以有了改良方案:每个程序(application file)有个默认的组编号,如果一个字符的组编号和默认的相同,则可以忽略不写(我没有找到设置这个组编号的方法,测试过程中它总是 0x01)。于是在默认组编号为 0x01 的情况下,上面的内容变成了这样:

13 d6 d0 13 ce c4 74 65 73 74

这样就有了中文占三字节,英文占一字节的结论。有了上面的背景知识,我们可以得到以下结果:

  • Len(“中文Test”) = 6,6 个字符
  • Lenb(“中文Test”) = 12,在 LotusScript 中占用 6×2 个字节
  • Lenbp(“中文Test”) = 8,按照操作系统的字符编码,占用 2×2+4 个字节
  • 值为”中文Test”的域大小为 10 (2×3+4)字节

顺便一提,由于 LotusScript 采用的编码与 Domino 环境中其他地方不同,所以每次读写域值、print 语句都会进行转换,所以减少这种转换可以提升性能。比如:

for i=1 to 100
    print i
next i

进行了 100 此编码转换,而

strTemp = ""
for i=1 to 100
    i = strTemp & i
next i
print strTemp

只进行了一次转换,所以性能上会有优势。

请参考:Computing Strings @Length

视图在 Domino 环境中起着重要的作用,它将文档按照定义好的方式组织起来,作为展现给用户的数据或者查找数据的索引。而保持视图中的数据随时更新,是由一个重要的服务器任务:索引器(Indexer)完成的。

索引器任务由 Update、Updall(Update all)两个任务组成,它们通过调用 Notes Index Facility (NIF) 和 Full-Text services,保持各视图和全文索引内容为最新。本文仅讨论视图和索引器任务相关的部分,全文索引相关内容并未涉及。

Update 任务默认写在 Notes.ini 文件的 ServerTasks 参数中,所以它是随服务器一起启动的,持续不断地运行,检查其工作队列以查找需要更新的视图和文件夹。Update 保持两个工作队列:一个即时队列,一个延迟队列。其他服务器组件,例如路由器(Router)和复制器(Replicator),在数据库发生修改时将请求投递给 Update 任务。有些请求投递为延迟,有些请求投递为即时。此请求只包含数据库的完整路径,不包含视图名。延迟队列请求在被处理之前会保持 15 秒,以便在此时间内更新同一数据库的请求作为重复请求而被忽略,通过统一处理来提高性能。这个 15 秒的延迟时间可以通过 Update_Suppression_Time 参数修改。

工作队列中记录了哪些数据库需要更新索引,那么数据库中的具体哪个视图需要更新呢?在数据库的头信息里面,记录了数据库的修改时间;同时在视图的索引信息里面也记录了上次更新索引的时间。通过比较两个时间就可以判断哪些视图需要更新。

Updall 与 Update 类似,但它不是持续不断地运行,也不使用队列;而是根据需要运行。默认情况下,Updall 包括在 NOTES.INI 设置 ServerTasksAt2 中,因此它在每天凌晨 2 点运行。在运行 Updall 时您可以指定选项,但是如果不指定这些选项,则 Updall 会更新服务器上所有数据库中,需要更新的任何视图索引或全文搜索索引。为节省磁盘空间,Updall 还从数据库中清除删除存根(deletion stubs ),并删除符合条件视图的视图索引。

在视图属性的高级页签中,有两个和索引相关的选项:刷新、废弃。先看看刷新选项:

  • 第一次使用后自动刷新
    新建视图时的默认选项,也是一个功能和性能比较均衡的选项,无特殊情况下推荐使用。在用户第一次访问之前,索引器不会更新它,减小了无用视图对性能的影响。用户第一次访问时建立视图索引,所以这次访问会比较慢。不过一旦索引建立起来,索引器就会负责更新它,从而保证用户访问时无需等待。
  • 自动刷新
    与上一个类似,只是不管用户是否使用过它。这个选项对于用户的体验是最好的,因为打开视图时一般来说无需等待就能查看最新的数据;但对服务器来说压力是最大的,因为即使视图从没有人使用过,依然需要更新它的索引。情谨慎使用。
  • 手工刷新
    索引器不更新视图索引,完全依赖用户手工操作,对于服务器来说压力最小。用户打开视图时没有任何延迟,但是看到的数据可能不是最新的。此情况下视图左侧会显示刷新图标,提示用户数据并非最新的,用户点击图标或者按 F9 刷新数据。但对于浏览器应用来说,没有任何方式可以触发索引更新,所以无法使用。
  • 间隔 n 小时自动刷新
    手工刷新和自动刷新的混合体。如果距上次更新索引的时间超过了 n 小时,与自动刷新类似;反之与手工刷新类似。用于可预知更新频率的视图,比如每天晚上定时任务会创建文档,则可以设定为 24 小时刷新一次。

废弃选项:

  • 如果闲置 45 天
    45 天内没有任何用户访问此视图,则删除其索引。可以通过 Default_Index_Lifetime_Days 参数修改。
  • 每次使用后
    用了就删,下次用再重新创建。此方式对服务器压力会很大,一般很少用到,除非真的几乎是一次性使用。
  • 如果闲置 n 天
    与第一个选项类似。

请参考:The Indexer and Its FunctionalityThe basics of Notes view index refreshingUpdall switches, Update and NIF – Notes indexing basicsIndexer tasks: Update and Updall