多个线程对文档的并发利用的制作方法

文档序号:6360699阅读:200来源:国知局
专利名称:多个线程对文档的并发利用的制作方法
多个线程对文档的并发利用背景电子文档在当今的工作环境中无所不在。例如,数百万的人每天使用和生成文字 处理文档、电子表格文档,及其他种类的文档。随着电子文档的重要性提高,人们期望软件 应用提供用于操纵电子文档的更强大的工具。例如,人们期望文字处理应用提供准确的语 法和拼写检查工具。然而,这样的工具常常计算量很大。由于这样的工具计算量很大,因此,使用这样 的工具会导致用户很容易发现的延迟。这样的延迟会导致用户感到受挫,因此,应该尽量最 少化。近年来,计算机的性能已经提高。然而,这种提高中的大部分是由于单个计算机现 在可以使用多个处理单元这一事实。例如,老式计算机只有一个处理单元,因此只能一次执 行一个程序。较新的计算机可以具有多个处理单元,因此可以同时执行多个程序。在某些情况下,在多个处理单元上执行的多个程序需要与电子文档中的相同数据 进行交互。例如,如果第一程序将向电子文档中的某些数据写入而同时第二程序尝试读取 该数据,则第二程序可能会读取损坏的数据。对此问题的典型的解决方案是在程序读取数 据之前程序锁定电子文档中的数据。当一个程序锁定数据时,没有其他程序可以向数据写 入。因此,如果另一线程希望向数据写入而数据被锁定,则另一线程不得不等到数据被解 锁。迫使另一线程等待会导致用户很容易发现的延迟。概述一种计算系统并发地执行构造器线程和至少一个读取器线程。构造器线程通过修 改文档的活动表示来修改文档。读取器线程使用文档的非活动表示来对文档执行操作。文 档的活动表示和文档的非活动表示存储在计算系统的存储器中。文档的活动表示和文档的 非活动表示不包括相同数据在存储器中的不同副本。当读取文档的任何非活动表示中的数 据时,确保逻辑一致性,而不锁定文档的任何非活动表示中的任何数据。提供本概述是为了介绍一些概念。这些概念在以下详细描述中进一步描述。本概 述并不旨在标识出所要求保护的主题的关键特征或必要特征,也不旨在用于帮助确定所要 求保护的主题的范围。附图简述

图1是示出了示例计算系统的框图。图2示出了示例文档树和表示文档树的元素阵列。图3示出了文档的示例表示。图4示出了当插入元素时文档的示例表示。图5示出了当删除元素时文档的示例表示。图6示出了当在现有片段内插入附加元素时文档的示例表示。图7示出了示例索引树。图8示出了用属于索引树的较新版本的替换节点覆盖的示例索引树。图9是示出了当应用启动时由应用执行的示例操作的流程图。
图10是示出了示例元素插入操作的流程图。
图11是示出了示例元素插入操作的延续的流程图。
图12是示出了示例元素插入操作的进一步延续的流程图。
图13是示出了示例元素插入操作的进一步延续的流程图。
图14是示出了示例元素删除操作的流程图。
图15是示出了示例元素删除操作的延续的流程图。
图16是示出了示例元素删除操作的延续的流程图。
图17是示出了示例元素删除操作的延续的流程图。
图18是示出了读取器线程的示例操作的流程图。
图19是示出了读取器线程的示例操作的流程图。
图20是示出了示例计算设备的框图。
详细描述
图I是示出了示例计算系统100的框图。如图I的示例所示,用户102使用计算系统100来访问应用104。应用104可使用户102与文档106进行交互。在各实施例中,应用104可以是各种类型的应用。例如,应用104可以是MICROSOFT WORD 文字处理应用、MICROSOFT OUTLOOKiiilli信系统、_MK:ROSOFT EXCEL i[l jN€格应用、MICROSOFT ONENOTE 笔记记录应用,或其他类型的文字处理应用、通信/电子邮件应用、电子表格应用、笔记记录应用,或其他类型的可使用户与文档进行交互的应用。因此,文档106可以是各种类型的文档。例如,文档106可以是文字处理文档、网页、电子邮件消息、电子表格文档,或另一种类型的文档。在各实施例中,用户102可以以各种方式与文档106进行交互。例如,在某些实施例中,用户102可以查看或编辑文档106中的内容。
为向用户102显示文档106,应用104将文档106的内部表示转换为向用户102示出的文档。例如,文档106的表示可包括指示应用104如何显示文档106的大量的数据。应用104解释此数据,以向用户102显示文档106。然而,此数据一般不向用户102显示。
应用104使用由计算系统100执行的多个线程来使用户102能够与文档106进行交互。线程是程序的可以独立于程序的其他部分执行的一部分。应用104所使用的线程可以在计算系统100的不同的处理单元上并发地执行。因此,线程中的两个或更多会试图同时访问文档106的表示中的相同数据。线程中的两个或更多同时访问相同数据是不希望的,因为会发生意外的结果。例如,当用户102向计算系统100提供输入以用新单词(例如, “leopard”)来替换文档106中的老单词(例如,“tiger”)时,一个线程更新文档106的表示中的适当的数据,以将新单词替换为老单词。同时,另一线程对文档进行拼写检查。如果进行拼写检查的线程读取适当的数据而更新的线程正在更新适当的数据,则进行拼写检查的线程可以读取表示新单词中的某一部分(例如,"Ieop”)的数据和表示老单词中的某一部分 (例如,“ger”)的数据。进行拼写检查的线程可能看到单词为“leopger”,并指示新单词拼写错误,尽管新单词“leopard”拼写正确并向用户102显示正确。这在逻辑上不一致。
为避免此情况,应用104使用文档106的多个表示。如图I的示例所示,线程包括构造器线程108。如在本说明书中别处所描述的,构造器线程108通过修改文档106的活动表示来修改文档106。文档106的活动表示存储在计算系统100的存储器中。在构造器线程108完成修改文档106的活动表示之后,文档106的活动表示变为文档106的非活动表
除构造器线程108之外,应用104使用一个或多个读取器线程IlOA到IlON(统称为“读取器线程” 110)。读取器线程110使用文档106的一个或多个非活动表示来对文档 106执行操作。这样的操作帮助应用104提供各种类型的功能。例如,文档106可以是诸如 MICROSOFT WORD 文档之类的文字处理文档。在此示例中,读取器线程110中的一个对文档106中的文本执行拼写检查操作。在另一示例中,读取器线程110中的一个使文档106准备好供打印。在再一个示例中,读取器线程110中的一个将文档106保存到本地或远程数据存储系统中。在再一个示例中,读取器线程110中的一个使用文档106的非活动表示以向用户102显示文档106。在再一个示例中,读取器线程110中的一个在用户102 向文档106中键入数据时对文档106重标页码。在再一个示例中,当单词横跨多行时,读取器线程110中的一个标识要插入连字符的位置。
构造器线程108是修改文档106的任何表示中的数据的唯一线程。即,读取器线程110不修改文档106的活动表示或文档106的任何非活动表示。相反地,读取器线程110 可以指示构造器线程108修改文档106。构造器线程108不修改文档106的任何非活动表示中的任何数据。
在构造器线程108完成修改文档106的活动表示的操作之后,文档106的活动表示变为文档106的非活动表示。文档106的此非活动表示可供读取器线程110使用。为再次修改文档106,构造器线程108生成文档106的新活动表示,修改文档106的该新活动表示,并使文档106的此新活动表示成为文档106的非活动表示。
由于没有线程修改文档106的任何非活动表示,因此,当读取器线程110读取文档 106的非活动表示中的数据时,确保了逻辑一致性,而不锁定文档106的非活动表示中的任何数据。换言之,没有当读取器线程110中的一个尝试读取数据时另一个并发地执行的线程会向该相同数据写入的危险。
每当文档106被修改时都生成文档106的完全独立的表示会消费计算系统100的存储器中的大量的空间。此外,每当文档106被修改时生成文档的完全独立的表示会计算量很大。因此,文档106的活动表示和文档106的非活动表示不包括相同数据在存储器中的不同副本。例如,文档106的活动表示和文档106的非活动表示两者都可以包括表示文档106的相同部分的数据。在此示例中,在存储器中没有该数据的两个独立的副本。相反地,文档106的活动表示和文档106的非活动表示两者都引用存储器中的该数据的相同副本。
图2示出了示例文档树202和元素阵列202。在内部,文档106被表示成诸如文档树200之类的文档树。文档树200是文档元素的层次结构。这些文档元素通常不向用户 102显示,而是被应用104用来确定如何向用户102显示文档106。
文档树200中的文档元素包括表示文档106内的结构的元素。例如,在图2的示例中,文档树200包括作为整体来表示文档106的文档元素204。在此示例中,文档树200 包括表示文档106内的段落的文档元素206和文档元素208。由于文档元素206(即,段落) 和文档元素208 (即,另一个段落)表示文档106内的东西,因此,文档元素206和文档元素 208在文档树200中的文档元素204之下。
此外,在图2的示例中,文档树200还包括文档元素210、文档元素212,以及文档元素214。文档元素210和文档元素212表示由文档元素206所表示的段落内的文本的顺串。例如,文档元素210和文档元素212可以表示由文档元素206所表示的段落中的句子。 由于文档元素210和文档元素212表示由文档元素206所表示的段落内的东西,因此,文档元素210和文档元素212在文档树200中的文档元素206之下。文档元素214表示由文档元素208所表示的段落内的文本的顺串。由于文档元素214表示由文档元素208所表示的段落内的东西,因此,文档元素214在文档树200中的文档元素208之下。
文档树200中的文档元素可以具有各种属性。在图2的示例中,文档元素204可包括将“Times New Roman”设置为文档106的默认字体的属性。在此示例中,文档元素208 可包括替换默认字体并将“Arial”设置为由文档元素208所表示的段落的字体的属性。此外,在此示例中,文档元素214可包括使由文档元素214所表示的文本的顺串带下划线的属性。
在概念上,计算机存储器看起来象一行插槽。该行中的每一个插槽都具有不同的地址。例如,该行中的一个插槽可以具有地址“37”,该行中的下一插槽可以具有地址“38” 等等。每一个插槽都可以存储数据。由于计算机存储器看起来象一行插槽,因此,计算机存储器在概念上是一维结构。相比之下,文档树200是二维结构(即,文档树200具有高度和宽度)。为将文档树200 (二维结构)存储在计算机存储器(一维结构)中,需要将文档树200 表不为一维结构。
元素阵列202是表示文档树200的示例一维结构。元素阵列202包括元素216A、 216B、218A、218B、220A、220B、222A、222B、224A、224B、226A,以及 226B。元素 216A 和 216B 对应于文档树200中的文档元素204。元素216A是打开的元素,元素216B是对应于元素216A 的关闭的元素。打开的元素和对应的关闭元素之间的阵列中的元素表示低于由打开的元素和对应的关闭的元素所表示的文档元素下面的文档元素。
元素216A和216B之间的元素阵列202中的元素对应于文档元素204下面的文档树200中的文档元素。元素218A和218B对应于文档树200中的文档元素206。元素218A 和218B之间的元素阵列202中的元素对应于文档元素206下面的文档树200中的文档元素。元素220A和220B对应于文档树200中的文档元素210。由于在文档元素210下面的文档树200中没有文档元素,因此,在元素220A和220B之间的元素阵列202中没有元素。 元素222A和222B对应于文档树200中的文档元素212。由于在文档元素210下面的文档树200中没有文档元素,因此,在元素222A和222B之间的元素阵列202中没有元素。元素 224A和224B对应于文档树200中的文档元素208。元素224A和224B之间的元素阵列202 中的元素对应于文档元素208下面的文档树200中的文档元素。元素226A和226B对应于文档树200中的文档元素214。由于在文档元素214下面的文档树200中没有文档元素,因此,在元素226A和226B之间的元素阵列202中没有元素。
在用户102处理文档106时,用户102可能希望在由文档元素206所表示的段落和由文档元素208所表示的段落之间添加新段落。因此,文档树200将被更新,以包括文档元素204下面的新文档元素。新文档元素表示新段落。为表示更新的文档树200,将需要在元素阵列202中的元素218B和224A之间添加新的一对元素。该对新元素对应于新文档元素。
如上文所提及的,计算机存储器在概念上是一行插槽。表示元素阵列202的数据存储在计算机存储器中的这样的插槽中。为在元素阵列202中的两个元素之间插入新元素,构造器线程108可以通过将新元素之后的元素阵列202中的所有元素复制到该行插槽的下游的插槽中,为新元素腾出插槽,然后,将新元素存储到腾出的插槽中。例如,元素218B 可以存储在插槽“ 37 ”,元素224A可以存储在插槽“ 38 ”,元素226A可以存储在插槽“ 39 ”, 元素226B可以存储在插槽“40”,元素224B可以存储在插槽“41”,而元素216B可以存储在插槽“41”。在此示例中,为在元素218B和元素224A之间插入元素,计算系统100可以将元素216B复制到插槽“43”,将元素224B复制到插槽“42”,将元素226B复制到插槽“41”, 将元素226A复制到插槽“40”,并将元素224A复制到插槽“39”。在此示例中,构造器线程 108可以将新元素存储在插槽“37”和“38”中。如此示例演示的,如果构造器线程108将使用此方法,构造器线程108可能必须执行大量的复制操作来将元素插入到元素阵列202中。 类似地,如果构造器线程108将在元素被从元素阵列202中删除时移动元素阵列202中的元素,则构造器线程108可能必须执行大量的复制操作来从元素阵列202中删除元素。
并非在新元素被插入到元素阵列202中时复制元素,构造器线程108将新元素添加到真实元素阵列的一端中。因此,真实元素阵列中的元素不一定被排序,以便对应于另一个文档元素下面的文档元素的元素在对应于其他文档元素的元素之间。如本说明书所描述的,文档106的表示包括索引树、片段描述符表,以及这样的真实元素阵列。索引树和片段描述符表指示真实元素阵列中的元素在虚拟元素阵列中的哪里。虚拟元素阵列是文档树 200的一维表示。虚拟元素阵列中的元素被排序,以便对应于另一个文档元素下面的文档元素的元素在对应于其他文档元素的元素之间。
图3是示出了文档106的示例表示的框图。文档106的表示包括索引树300、片段描述符表302,以及真实元素阵列304。索引树300和片段描述符表302是指示真实元素阵列304中的元素在虚拟元素阵列306中的哪里的数据结构。
如图3的示例所示,真实元素阵列304包含元素308A、308B、310A、310B、312A,以及 312B。元素308A、308B、310A、310B、312A,以及312B对应于文档106的文档树中的每一个文档元素。对于虚拟元素阵列306中的每一个给定元素,如果给定元素在虚拟元素阵列306中的打开的元素和关闭的元素之间,则给定元素表示文档树中的低于由打开的元素和关闭的元素所表示的文档树中的文档元素的文档元素。虚拟元素阵列306还包含元素308A、308B、 310A、310B、312A,以及312B。然而,虚拟元素阵列306不实际存在于计算机存储器中。
在诸如图3的示例中所示出的之类的某些实施例中,当应用104最初加载文档106 时,真实元素阵列304中的元素被适当地排序。换言之,真实元素阵列304中的对应于低于另一文档元素的文档元素的每一个元素都在对应于其他文档元素的元素之间。因此,当应用104最初加载文档106时,真实元素阵列304可以与虚拟元素阵列306相同。
片段描述符表302包含一组一个或多个片段描述符。片段描述符表302中的片段描述符中的每一个都是标识真实元素阵列304的不同的片段的数据结构。真实元素阵列 304的片段是真实元素阵列304中的一组一个或多个连续的元素。例如,元素308A、310A, 以及310B可以是真实元素阵列304的片段,而元素312B和308B可以是真实元素阵列304 的另一片段。
在各实施例中,片段描述符是以各种方式实现的。例如,在某些实施例中,片段描述符指定片段的最左边的元素的真实偏移量以及片段的最右边的元素的真实偏移量。在本说明书中,当一个元素比另一元素更接近于阵列的开始处时,可以说阵列中的元素在阵列中的另一个元素的左边。类似地,当一个元素比另一元素更远离阵列的开始处时,可以说阵列中的元素在阵列中的另一个元素的右边。在其他实施例中,片段描述符被实现为具有真实偏移属性和长度属性的数据结构。元素的真实偏移量指示从真实元素阵列304的开始处到元素的距离。片段描述符的真实偏移属性指示片段中的最左边的元素的真实偏移量。片段描述符的长度属性指示片段的长度。片段描述符的此实现用于整个本说明书中。然而, 应该理解,在其他实施例中,也可以使用片段描述符的其他实现。
片段描述符的真实偏移属性可以以各种方式指示真实偏移量。例如,在某些实施例中,真实偏移属性可以指示从真实元素阵列304的开始处到元素的字节的数量。在其他实施例中,真实偏移属性可以指示真实元素阵列304的开始处和元素之间的元素的数量。 在整个本说明书中描述了真实偏移属性指示了元素的数量的各实施例。然而,应该理解,在某些实施例中,真实偏移属性可以以其他方式指示与真实元素阵列304的开始处的距离。
片段描述符的长度属性以各种方式指示片段的长度。例如,在某些实施例中,长度属性可以指示片段中的字节的数量。在其他实施例中,长度属性可以指示片段中的元素的数量。在整个本说明书中描述了长度属性指示了元素的数量的各实施例。然而,应该理解, 在其他实施例中,长度属性可以以其他方式指示片段的长度。
当计算系统100最初加载文档106时,在真实元素阵列304中只有一个片段。因此,片段描述符表302包括单个片段描述符314。片段描述符314具有真实偏移属性0,从而指示从真实元素阵列304的开始处开始的片段。片段描述符314具有长度属性6,表示片段是六个元素长。
索引树300包括一个或多个索引节点的层次结构。索引树300中的索引节点中的每一个都对应于片段描述符表302中的不同的片段描述符。如图3的示例所示,片段描述符表302中只有一个片段描述符314。因此,索引树300包含单个索引节点316。
在各实施例中,索引树300中的索引节点是以各种方式实现的。例如,在某些实施例中,索引树300中的索引节点被实现为具有左子节点属性、右子节点属性,以及描述符属性的数据结构。在这样的实施例中,如果索引节点在索引树300中具有左子索引节点,则索引节点的左子节点属性指示索引节点的左子节点属性。如果索引节点在索引树300中具有右子索引节点,则索引节点的右子节点属性指示索引节点的右子节点属性。索引节点的描述符属性指示片段描述符表302中的片段描述符。在图3的示例中,索引节点316的描述符属性指示片段描述符314。在整个本说明书中描述了其中索引节点被实现为具有左子节点属性、右子节点属性,以及描述符属性的数据结构的各实施例。然而,应该理解,在其他实施例中,索引节点是以其他方式实现的。
图4是示出了当插入元素时文档106的示例表示的框图。如图4的示例所示,元素402A、402B、404A、以及404B被插入在真实元素阵列304的一端。元素402A和402B表示低于由元素310A和310B所表示的文档元素的文档元素。元素404A和404B表示低于由元素310A和310B所表示的文档元素的文档元素。因此,在虚拟元素阵列306中,元素402A、 402B、404A,以及404B在元素3IOA和3IOB之间。
以前,真实元素阵列304中的所有元素都被适当地排序。因此,只需要一个片段描述符314来指示真实元素阵列304的包括元素308A和308B之间的元素的真实元素阵列10304的片段。当元素402A、402B、404A、以及404B被插入到真实元素阵列304中时,真实元素阵列304中的元素不再被适当地排序。相反,真实元素阵列304中的元素被分成三个片段包含属于元素402A、402B、404A,以及404B的左侧的元素(即,元素308A和310A)的真实元素阵列304的片段,包含元素402A、402B、404A,以及404B的真实元素阵列304的片段, 以及,包含属于元素402A、402B、404A,以及404B的右侧的元素(S卩,元素310B、312A、312B, 以及308B)的真实元素阵列304的片段。
片段描述符的属性的值不能改变是片段描述符表302的属性。此属性可以确保, 读取器线程110可以从片段描述符中读取数据,而无需考虑构造器线程108在读取器线程 110正在读取片段描述符中的数据时会改变片段描述符中的数据的可能性。
由于片段描述符的属性的值不改变,并且由于片段描述符只能指示真实元素阵列 304中的一个片段,因此,需要附加片段描述符。为添加附加片段描述符,构造器线程108 生成片段描述符406、片段描述符408,以及片段描述符410。片段描述符406、片段描述符 408,以及片段描述符410构成片段描述符表302的活动版本。片段描述符表302的活动版本是文档106的活动表不的一部分。
片段描述符406替换片段描述符314。然而,构造器线程108不立即删除片段描述符314。相反地,片段描述符314继续作为文档106的非活动表示中的片段描述符表302 的非活动版本的一部分而存在。因此,读取器线程110在构造器线程108正在对片段描述符表302的活动版本中的片段描述符执行操作时可以使用片段描述符314。
片段描述符406标识包含元素308A和310A的真实元素阵列304的片段。请注意, 片段描述符406是片段描述符314的克隆(即,副本),只是片段描述符406的长度属性不同于片段描述符314的长度属性。片段描述符408标识包含元素310B、312A,312B,以及308B 的真实元素阵列304的片段。片段描述符410标识包含元素402A、402B、404A,以及404B的真实元素阵列304的片段。
索引树300中的索引节点可以最多具有两个子节点。索引树300中的索引节点的两个子树的高度相差至多一个。例如,当索引节点的左子树的深度是I时,索引节点的右子树的深度无法是3。在另一示例中,当左子树的深度是I时,索引节点的右子树的深度可以是2、I或O。在某些实施例中,索引树300是AVL树、B树、红-黑树,或另一种二叉树。
索引树300具有排序属性。排序属性规定,对于索引树300中的每一个索引节点, 与索引节点的左子树中的索引节点相关联的元素具有小于与索引节点相关联的元素的虚拟偏移量的虚拟偏移量。此外,与索引节点的右子树中的索引节点相关联的元素具有大于与索引节点相关联的元素的虚拟偏移量的虚拟偏移量。当元素位于由索引节点所指示的片段描述符所指示的片段中时,元素与索引节点相关联。元素的虚拟偏移量是从虚拟元素阵列306的开始处到虚拟元素阵列306中的元素的位置的距离。
另外,索引节点的属性的值不能改变也是索引树300的属性。此属性可以确保,读取器线程Iio可以从索引节点中读取数据,而无需考虑构造器线程108在读取器线程110 正在读取索引节点中的数据时会改变索引节点中的数据的可能性。
为在元素402A、402B、404A,以及404B被插入到真实元素阵列304中时保持这些属性,构造器线程108生成索引节点412,414,以及416。索引节点412,414,以及416构成索引树300的活动版本。索引树300的活动版本是文档106的活动表示的一部分。
索引节点414替换索引节点316。然而,构造器线程108不立即删除索引节点316。 相反地,索引节点316继续作为文档106的非活动表示中所包括的索引树300的非活动版本的一部分而存在。因此,读取器线程110在构造器线程108正在执行操作以修改索引树 300的活动版本时可以使用索引节点316。索引节点412指示片段描述符406,索引节点414 指示片段描述符410,而索引节点416指示片段描述符408。
索引节点412位于索引节点414的左子树中。因此,索引节点412与具有小于与索引节点414相关联的元素的虚拟偏移量的虚拟偏移量的元素相关联。索引节点416位于索引节点414的右子树中。因此,索引节点416与具有大于与索引节点414相关联的元素的虚拟偏移量的虚拟偏移量的元素相关联。
在图4的示例中,文档106的活动表示包括索引树300的活动版本,片段描述符表 302的活动版本以及真实元素阵列304。当构造器线程108完成插入元素402A、402B、404A, 以及404B的操作时,索引树300的活动版本包括索引节点412、414,以及416,片段描述符表302的活动版本包括片段描述符406、408以及410。文档106的非活动表示包括索引树 300的非活动版本,片段描述符表302的非活动版本以及真实元素阵列304。索引树300的非活动版本仅仅包括索引节点316。片段描述符表302的非活动版本仅仅包括片段描述符 314。
图5示出了当删除元素时文档106的示例表示。如图5的示例所示,从虚拟元素阵列306中删除元素402A和402B。在真实元素阵列304中,元素402A和404B之后的元素不移动。S卩,在真实元素阵列304中,当从虚拟元素阵列306中删除元素402A和402B时,不使元素404A靠近元素308B。然而,在虚拟元素阵列306中,表现为好像元素402A和402B已经完全消失。
当元素402A和402B被删除时,片段描述符410的真实偏移属性和长度属性的值需要改变,以便指示片段不包括元素402A和402B。如上文所提及的,片段描述符的属性的值不能改变是片段描述符表302的属性。因此,构造器线程108生成片段描述符500。片段描述符500、片段描述符408,以及片段描述符406构成片段描述符表302的活动版本。片段描述符500替换片段描述符410。片段描述符500的真实偏移属性和长度属性具有适当的值。
尽管构造器线程108生成了片段描述符500,但是,索引节点414的描述符属性仍指示片段描述符410。如上文所提及的,索引节点的属性的值不能改变是索引树300的属性。因此,构造器线程108生成新索引节点502。索引节点502、414,以及416构成索引树 300的活动版本。索引节点502替换索引节点414。索引节点502的描述符属性指示片段描述符500。构造器线程108不立即删除索引节点414。这可使读取器线程110在构造器线程108修改索引树300的活动版本和片段描述符表302的活动版本时继续使用索引节点 414和片段描述符410。
应该理解,索引节点316和片段描述符314仍可以存在,供不使用索引节点414作为索引树300的根节点的读取器线程110使用。根索引节点是没有先辈节点的索引节点。 然而,为了清楚起见,图5中省略了索引节点316和片段描述符314。
图6示出了当在现有片段内插入附加元素时文档106的示例表示。如图6的示例中,构造器线程108将元素600A和600B插入到真实元素阵列304中。在虚拟元素阵列306中,元素600A和600B属于元素312A和312B之间。换言之,元素600A和600B表示低于由文档树200中的元素312A和312B所表示的文档元素的文档元素。
为确保元素600A和600B在虚拟元素阵列306中具有正确的位置,构造器线程108 创建新片段描述符602。片段描述符602标识包含元素600A和600B的真实元素阵列304 的片段。由于包含元素600A和600B的片段在逻辑上在包含元素310B、312A、312B,以及 308B的片段内发生,因此,构造器线程108生成片段描述符604和606。片段描述符406、 606、500、604,以及602构成片段描述符表302的活动版本。片段描述符604指示包含具有大于元素600A和600B的虚拟偏移量的虚拟偏移量的元素的真实元素阵列304的片段。片段描述符606指示包含具有小于元素600A和600B的虚拟偏移量的虚拟偏移量的元素的真实元素阵列304的片段。片段描述符606替换片段描述符408。
然后,构造器线程108生成索引节点608和610。索引节点608的描述符属性指示片段描述符606。索引节点610的描述符属性指示片段描述符604。由于索引节点608和 610与元素600A和600B的左边和右边的元素相关联,因此,索引节点608和610需要是与元素600A和600B相关联的索引节点的子节点。因此,索引节点416的左子节点属性、右子节点属性,以及描述符属性将需要改变。由于索引节点416不被允许改变,因此,构造器线程108生成索引节点612以替换索引节点416。索引节点612的左子节点属性指示索引节点608。索引节点612的右子节点属性指示索引节点610。索引节点612的描述符属性指不片段描述符602。
此外,索引节点502的右子节点属性还应该改变以指示新索引节点612。由于索引节点502不被允许改变,因此,构造器线程108生成索引节点614。索引节点614的左子节点属性继续指示索引节点412,索引节点614的右子节点属性指示索引节点612,而索引节点614的描述符属性继续指示片段描述符500。因此,在图6的示例中,索引节点614、412、 612,608,以及610构成索引树300的活动版本。
应该理解,图4、5,以及6只示出了构造器线程108对索引树300和片段描述符表 302执行的动作的某些组合,以维持真实元素阵列304和虚拟元素阵列306之间的适当的关系O
图7示出了示例索引树700。索引树700包括15个索引节点702到730。在图7 的示例中,在索引节点内示出了索引节点的左子树的大小。例如,索引节点702的左子树的大小是七,因为在索引节点702的左子树中有七个索引节点。
索引节点的左子树的大小不改变是索引树700的属性。因此,在构造器线程108将在任何索引节点的左子树中的索引节点添加到索引树700中的任何时间,构造器线程108 为索引节点的所有先辈索引节点生成替换索引节点。然而,为将单个的索引节点添加到索引树700中,构造器线程108不需要为不是新索引节点的先辈索引节点的索引节点生成任何替换。图4和6的示例演示了此属性。
图8示出了用属于索引树700的较新版本的替换节点来覆盖的索引树700。在图8 的示例中,构造器线程108将索引节点802添加到索引树700中。因此,构造器线程108生成替换索引节点804、806、808,以及810。在索引树700的较高版本中,替换索引节点804、 806,808,以及810替换索引节点718、708、704,以及702。
图9是示出了当应用104启动时由应用104执行的示例操作900的流程图。如图9的示例所示,当应用104启动时(902)操作900开始。在各实施例中,应用104响应于各种事件而启动。例如,在某些实施例中,当用户102指示计算系统100的操作系统启动应用 104时,应用104启动。在其他实施例中,应用104响应于来自另一应用的请求而启动。
在应用104启动之后,应用104从本地或远程数据存储系统将文档106读取到存储器(904)中。在某些实施例中,应用104不在启动之后立即将文档106读取到存储器中, 而是在读取文档106之前等待某个事件。例如,当应用104接收到来自用户102的打开文档106的输入时,应用104可以读取文档106。当应用104将文档106读取到存储器中时, 应用104将表示文档106中的文档元素的元素存储在真实元素阵列304中。
接下来,应用104生成片段描述符表302 (906)。如图3的示例所示,片段描述符表302最初只包含一个片段描述符。然后,应用104生成索引树300 (908)。如图3的示例所示,索引树300最初只包含一个索引节点。索引节点的描述符属性指示片段描述符表 302中的片段描述符。
在生成片段描述符表302和索引树300之后,应用104设直当如树指针以指不索引树300中的单个索引节点(910)。如下面参考图19所描述的,读取器线程110使用当前树指针以确定索引树300的最近可用的非活动版本的根索引节点。
在应用104设置当前树指针之后,应用104唤醒构造器线程108(912)。唤醒线程是使线程开始运行的过程。在构造器线程108醒来之后,构造器线程108可以响应于用户的修改文档106的输入,来修改文档106的活动表不。
每当构造器线程108接收到修改文档106的输入时,构造器线程108执行生成文档106的新活动表示的操作。在构造器线程108完成该操作之后,文档106的新的活动表示变为可供读取器线程110使用的文档106的非活动表示。例如,在某些实施例中,构造器线程108执行元素插入操作和元素删除操作。每当构造器线程108执行元素插入操作时,构造器线程108都生成文档106的新活动表示,其中,虚拟元素阵列306包括一个或多个附加元素。在元素插入操作结束时,文档106的新的活动表示变为可供读取器线程110使用的文档106的非活动表示。图10-13示出了元素插入操作的示例实现。每当构造器线程108 执行元素删除操作时,构造器线程108都生成文档106的新活动表示,其中,虚拟元素阵列 306包括较少的元素。在元素删除操作结束时,文档106的新的活动表示变为可供读取器线程110使用的文档106的非活动表示。图14-18示出了元素删除操作的示例实现。
接下来,应用104唤醒一个或多个读取器线程110(914)。一个或多个读取器线程 110中的每一个都执行最初检查当前树指针以确定索引树300的最近可用的非活动版本的根索引节点的操作。在由读取器线程110执行的操作的整段时期内,读取器线程110使用该索引节点和由该索引节点的左和右子节点属性所指示的索引节点来访问真实元素阵列304 中的元素。换言之,在由读取器线程110执行的操作的过程中,读取器线程110不开始查看索引树300的较新版本。读取器线程110可以执行重复的操作。当由读取器线程110中的一个执行的操作重复时,读取器线程可以再次查看当前树指针以确定索引树300的最近可用的非活动版本的根索引节点。
由于构造器线程108和读取器线程110可以并发地执行,由于构造器线程108不修改文档106的非活动表示,并且由于读取器线程110不从文档106的活动表示中读取,因此,确保了文档106的非活动表示的逻辑一致性,而不锁定文档106的非活动表示中的数据。因此,构造器线程108可以在读取器线程110并发地从文档106的一个或多个非活动表示中读取给定元素时从文档106的活动表示中删除同一个给定元素。在此示例中,给定元素表示文档106的文档树中的同一个文档。
图10是示出了示例元素插入操作1000的流程图。如图10的示例所示,当构造器线程108接收到指示元素将被插入到文档106中的输入时(1002),元素插入操作1000开始。在各实施例中,构造器线程108可以以各种方式接收这样的输入。例如,构造器线程 108可以监听来自应用104的用户的键盘输入。在另一示例中,构造器线程108可以监听来自应用104的另一线程或另一应用的插入元素的指令。
响应于接收到输入,构造器线程108将一个或多个元素插入到真实元素阵列304 中(1004)。插入的元素变为真实元素阵列304的新的片段。在各实施例中,构造器线程108 以各种方式将元素插入到真实元素阵列304中。例如,在某些实施例中,对于至少某些类型的文档元素,构造器线程108将打开的元素和关闭的元素插入到真实元素阵列304中。在这样的实施例中,对于其他类型的元素,构造器线程108将单个元素插入到真实元素阵列304 中。
接下来,构造器线程108设置当前节点指针以指示索引树300的最近可用的非活动版本的根索引节点(1006)。在本说明书中,当前索引节点是由当前节点指针所指示的索引节点。此外,在本说明书中,当前片段描述符还是由当前索引节点所指示的片段描述符。 此外,在本说明书中,当前片段描述符还是由当前片段描述符所指示的真实元素阵列304 的片段。
在设置当前节点指针之后,构造器线程108确定新片段的虚拟偏移量是否小于当前片段的虚拟偏移量(1008)。新片段是包含插入的元素的真实元素阵列304的片段。新片段的虚拟偏移量是从虚拟元素阵列306的开始处到插入的元素的最左边的元素的距离。当前片段的虚拟偏移量是从虚拟元素阵列306的开始处到当前片段中的最左边的元素的距离。
如果新片段的虚拟偏移量小于当前片段的虚拟偏移量(1008的“是”),则构造器线程108使当前索引节点进栈到堆栈上(1010)。在各实施例中,构造器线程108以各种方式使当前索引节点进栈到堆栈上。例如,在某些实施例中,构造器线程108通过使指向当前索引节点的指针进栈到堆栈上来使当前索引节点进栈到堆栈上。
在使当前索引节点进栈到堆栈上之后,构造器线程108设置当前节点指针以指示当前索引节点的左子节点属性(1012)。通过设置当前节点指针以指示当前索引节点的左子节点属性,当前索引节点的左子节点属性变为“当前”索引节点。然后,构造器线程108再次确定新片段的虚拟偏移量是否小于当前片段的虚拟偏移量(1008)。只要新片段的虚拟偏移量小于当前片段的虚拟偏移量,构造器线程108就持续重复步骤1010和1012。
如果新片段的虚拟偏移量不小于当前片段的虚拟偏移量(1008的“否”),则构造器线程108确定新片段的虚拟偏移量是否与当前片段的虚拟偏移量相同(1014)。如果构造器线程108确定新片段的虚拟偏移量与当前片段的虚拟偏移量相同(1014的“是”),则构造器线程108执行图11中所示出的操作“A”。在构造器线程108执行操作“A”之后,构造器线程108执行图13中所示出的操作“C”,以完成元素插入操作1000。
如果构造器线程108确定新片段的虚拟偏移量不与当前片段的虚拟偏移量相同(1014的“否”),则构造器线程108确定新片段的虚拟偏移量是否在当前片段的虚拟偏移量的范围内(1016)。如果构造器线程108确定新片段的虚拟偏移量在当前片段的的虚拟偏移量的范围内(1016的“是”),则构造器线程108执行图12中所示出的操作“B”。在构造器线程108执行操作“B”之后,构造器线程108执行图13中所示出的操作“C”,以完成元素插入操作1000。
如果构造器线程108确定新片段的虚拟偏移量不在当前片段的虚拟偏移量的范围内(1016的“否”),则构造器线程108使当前索引节点进栈到堆栈上(1018)。在使当前索引节点进栈到堆栈上之后,构造器线程108设置当前节点指针以指示当前索引节点的右子节点属性(1020)。通过设置当前节点指针以指示当前索引节点的右子节点属性,当前索引节点的右子节点属性变为“当前”索引节点。在设置当前节点指针以指示当前索引节点的右子节点属性之后,构造器线程108再次确定新片段的虚拟偏移量是否小于当前片段的虚拟偏移量(1008),依次类推。
图11是示出了示例元素插入操作1000的延续1100的流程图。如图11的示例所示,当构造器线程108克隆当前索引节点时(1102),延续1100开始。在本说明书中,每当构造器线程108 “克隆”当前索引节点时,构造器线程108生成此处被称为克隆的当前索引节点的新索引节点。克隆的当前索引节点,至少一开始,与当前索引节点具有相同左子节点属性、右子节点属性,以及描述符属性。以此方式,如果当前索引节点具有左子节点属性,则当前索引节点的左子节点属性变为克隆的当前索引节点的左子节点属性。此外,如果当前索引节点具有右子节点属性,则当前索引节点的右子节点属性变为克隆的当前索引节点的右子节点属性。此外,当构造器线程108克隆当前索引节点时,构造器线程108配置克隆的当前节点的描述符属性以指示当前片段描述符。
在克隆当前索引节点之后,构造器线程108生成新索引节点(1104)。类似于其他索引节点,新索引节点具有左子节点属性、右子节点属性,以及描述符属性。构造器线程108 设置新索引节点的左子节点属性以指示当前索引节点的左子节点属性(1106)。以此方式, 当前索引节点的左子节点属性变为新索引节点的左子节点属性。
接下来,构造器线程108配置克隆的索引节点的左子节点属性以指示新索引节点 (1108)。以此方式,新索引节点变为克隆的当前索引节点的左子节点属性。
然后,构造器线程108生成新片段描述符(1110)。新片段描述符指示包含插入的元素的真实元素阵列304的片段。然后,构造器线程108设置新索引节点的描述符属性以指示新片段描述符(1112)。
然后,构造器线程108重新平衡当前子树(1114)。在重新平衡当前子树之后,构造器线程108执行图13中所示出的操作“C”以完成元素插入操作1000。当前子树是克隆的当前索引节点的左子树,克隆的当前索引节点,以及克隆的当前索引节点的右子树。
当当前子树被重新平衡时,当前子树中的索引节点被重新排列,以便索引树中的每一个节点的左子树的深度和右子树的深度相差不超过一个。此外,当当前子树被重新平衡时,当前子树还维持排序属性。排序属性规定,对于当前子树中的每一个给定索引节点, 给定索引节点的左子树中的索引节点与具有小于与给定索引节点相关联的元素的虚拟偏移量的虚拟偏移量的元素相关联,而给定索引节点的右子树中的索引节点与具有大于与给定索引节点相关联的元素的虚拟偏移量的虚拟偏移量的元素相关联。已知有多个现有的用于重新平衡诸如当前索引树之类的AVL树的“树旋转”算法。
为在重新平衡过程中重新排列当前树中的索引节点,构造器线程108改变当前子树中的某些索引节点的左或右子节点属性。如果构造器线程108需要改变当前子树中的给定索引节点的左或右子节点属性,则在改变给定索引节点的左或右子节点属性之前,构造器线程108克隆给定索引节点。
图12是示出了示例元素插入操作1000的延续1200的流程图。如图12的示例所示,当构造器线程108克隆当前索引节点时(1202),延续1200开始。然后,构造器线程108 生成第一新索引节点(1204)。如果存在当前索引节点的左子节点属性,则构造器线程108 配置第一新索引节点的左子节点属性以指示当前索引节点的左子节点属性(1206)。以此方式,当前索引节点的左子节点属性变为第一新索引节点的左子节点属性。然后,构造器线程 108配置克隆的当前索引节点的左子节点属性以指示第一新索引节点(1208)。以此方式, 第一新索引节点变为克隆的当前索引节点的左子节点属性。
接下来,构造器线程108克隆当前片段描述符(1212)。当构造器线程108克隆当前片段描述符时,构造器线程108生成此处被称为克隆的当前片段描述符的新片段描述符。 克隆的当前片段描述符最初与当前片段描述符具有相同偏移属性和长度属性。构造器线程 108修改克隆的当前片段描述符(1212)。构造器线程108修改克隆的当前片段描述符,以便当前片段仅限于具有小于插入的元素的虚拟偏移量的虚拟偏移量的元素。例如,如果当前片段包括具有真实偏移量10到20的元素,则当前片段描述符的长度属性是21。在此示例中,插入的元素具有具有真实偏移量15和16的元素的虚拟偏移量之间的虚拟偏移量。因此,在此示例中,构造器线程108修改克隆的当前片段描述符的长度属性,以便长度属性具有值6而不是21。然后,构造器线程108配置第一新索引节点的描述符属性以指示克隆的当前片段描述符(1214)。
接下来,构造器线程108生成第一新片段描述符(1216)。第一新片段描述符指示当前片段。然后,构造器线程108配置克隆的当前索引节点的描述符属性以指示第一新的片段描述符(1218)。
然后,构造器线程108生成第二新索引节点(1220)。如果当前索引节点的右子节点属性存在,则构造器线程108配置第二新索引节点,以便当前索引节点的右子节点属性是第二新索引节点的右子节点属性(1222)。接下来,构造器线程108配置克隆的当前索引节点的右子节点属性,以便克隆的当前索引节点的右子节点属性指示第二新索引节点 (1224)。
然后,构造器线程108生成第二新片段描述符(1226)。第二新片段描述符指示以前在当前片段中的具有大于插入的的元素的虚拟偏移量的虚拟偏移量的元素。例如,如果当前片段包括具有真实偏移量10到20的元素并且最左边的插入的元素具有在具有真实偏移量15和16的元素的虚拟偏移量之间的虚拟偏移量,则第二新片段描述符具有偏移属性 16和长度属性5。在此示例中,具有16和20之间的真实偏移量的元素是以前在当前片段中的并且具有大于插入的元素的虚拟偏移量的虚拟偏移量的元素。
然后,构造器线程108配置第二新索引节点的描述符属性以指示第二新片段描述符(1228)。在配置第二新索引节点的描述符属性以指示第二新片段描述符之后,构造器线程108,在必要时重新平衡当前子树(1230)。在重新平衡当前子树之后,构造器线程108执行图13中所示出的操作“C”以完成元素插入操作1000。
图13是示出了示例元素插入操作1000的延续1300的流程图。如图13的示例所示,当构造器线程108设置当前节点指针以指示克隆的当前索引节点时(1302),延续1300 开始。以此方式,克隆的当前索引节点变为“当前”索引节点。
接下来,构造器线程108确定堆栈上是否有任何索引节点(1304)。如果在堆栈上有一个或多个索引节点,则构造器线程108使一索引节点从堆栈中退栈(1306)。然后,构造器线程108克隆该已退栈索引节点(1308)。当构造器线程108克隆已退栈索引节点时,构造器线程108生成此处被称为克隆的已退栈索引节点的新索引节点。当构造器线程108克隆已退栈索引节点时,克隆的已退栈索引节点的左子节点属性、右子节点属性,以及描述符属性与已退栈索引节点的左子节点属性、右子节点属性,以及描述符属性相同。
在克隆已退栈索引节点之后,构造器线程108确定与已退栈索引节点相关联的片段的虚拟偏移量是否小于与当前索引节点相关联的片段的虚拟偏移量(1310)。如果与已退栈索引节点相关联的片段的虚拟偏移量小于与当前索引节点相关联的片段的虚拟偏移量 (1310的“是”),则构造器线程108设置克隆的已退栈索引节点的左子节点属性以指示当前索引节点(1312)。以此方式,当前索引节点变为克隆的已退栈索引节点的左子节点属性。
否则,如果与已退栈索引节点相关联的片段的虚拟偏移量不小于(S卩,大于)与当前索引节点相关联的片段的虚拟偏移量(1310的“否”),则构造器线程108设置克隆的已退栈索引节点的右子节点属性以指示当前索引节点(1314)。以此方式,当前索引节点变为克隆的已退栈索引节点的右子节点属性。
在设置克隆的已退栈索引节点的左或右子节点属性之后,构造器线程108设置当前节点指针,以指示克隆的已退栈索引节点(1316)。以此方式,克隆的已退栈索引节点变为“当前”索引节点。在设置当前节点指针以表示克隆的已退栈索引节点之后,构造器线程 108再次确定堆栈上是否有任何索引节点(1304)。如果在堆栈上有索引节点,则构造器线程108重复步骤1306、1308、1310、1312或1314、1316,以及1318。否则,如果在堆栈上没有索引节点,则构造器线程108设置当前树指针以指示当前索引节点(1320)。在设置当前树指针以指示当前索引节点之后,元素插入操作1000完成。此外,在构造器线程108设置当前树指针之后,文档106的活动表示变为文档106的最近可用的非活动表示。
图14是示出了示例元素删除操作1400的流程图。如图14的示例所示,当构造器线程108接收到指示元素将被从文档106中删除的输入时(1402),元素删除操作1400开始。
响应于接收到输入,构造器线程108设置当前节点指针以指示索引树300的最近可用的非活动版本最近的根索引节点(1404)。换言之,构造器线程108设置当前节点指针等于当前树指针。
接下来,构造器线程108确定最左边的删除的元素的虚拟偏移量是否小于当前片段的虚拟偏移量(1406)。当前片段是由当前索引节点所指示的片段描述符所指示的真实元素阵列304的片段。如果最左边的删除的元素的虚拟偏移量小于当前片段的虚拟偏移量 (1406的“是”),则构造器线程108使当前索引节点进栈到堆栈上(1408)。在使当前索引节点进栈到堆栈上之后,构造器线程108设置当前节点指针以指示当前索引节点的左子节点属性(1410)。以此方式,当前索引节点的左子节点属性变为“当前”索引节点。在设置当前18节点指针之后,构造器线程108再次确定最左边的删除的元素的虚拟偏移量是否小于当前片段的虚拟偏移量(1406)。只要最左边的删除的元素的虚拟偏移量小于当前片段的虚拟偏移量,构造器线程108就持续重复步骤1408和1410。
如果最左边的删除的元素的虚拟偏移量不小于当前片段的虚拟偏移量(1406的 “不是”),则构造器线程108确定最左边的删除的元素的虚拟偏移量是否与当前片段的虚拟偏移量相同(1412)。如果构造器线程108确定最左边的删除的元素的虚拟偏移量与当前片段的虚拟偏移量相同(1412的“是”),则构造器线程108执行图15中所示出的操作“A”。在构造器线程108执行操作“A”之后,构造器线程108执行图18中所示出的操作“C”,以完成元素删除操作1400。
如果构造器线程108确定最左边的删除的元素的虚拟偏移量不与当前片段的虚拟偏移量相同(1412的“否”),则构造器线程108确定最左边的删除的元素是否在当前片段的虚拟偏移量的范围内(1414)。如果构造器线程108确定最左边的删除的元素的虚拟偏移量在当前片段的的虚拟偏移量的范围内(1414的“是”),则构造器线程108执行图16中所示出的操作“B”。在构造器线程108执行操作“B”之后,构造器线程108执行图18中所示出的操作“C”,以完成元素删除操作1400。
否则,如果构造器线程108确定最左边的删除的元素的虚拟偏移量不在当前片段的虚拟偏移量的范围内(1414的“否”),则构造器线程108使当前索引节点进栈到堆栈上(1416)。然后,构造器线程108设置当前节点指针以指示当前索引节点的右子节点属性 (1418)。以此方式,当前索引节点的右子节点属性变为“当前”索引节点。在设置当前节点指针以指示当前索引节点的右子节点属性之后,构造器线程108确定最左边的删除的元素的虚拟偏移量是否小于当前片段的虚拟偏移量(1406)。构造器线程108持续执行步骤 1406、1408、1410、1412、1414、1416,以及1418,直到最左边的删除的元素的虚拟偏移量与当前片段的虚拟偏移量相同或者最左边的删除的元素在当前片段的虚拟偏移量的范围内。
图15是示出了示例元素删除操作1400的延续1500的流程图。如图15的示例所示,当构造器线程108确定删除的元素是否是当前片段中的全部元素(1502)时,延续1500 开始。
如果删除的元素不是当前片段中的全部元素(1502的“否”),则构造器线程108克隆当前片段描述符(1504)。当构造器线程108克隆当前片段描述符时,构造器线程108生成此处被称为克隆的当前片段描述符的新片段描述符。克隆的当前片段描述符最初与当前片段描述符具有相同偏移属性和长度属性。
然后,构造器线程108修改克隆的当前片段描述符的偏移属性,以便真实偏移属性指示当前片段在最右边删除的元素之后的当前片段中的最左边的元素的虚拟偏移量处启动(1506)。例如,如果当前片段包括真实偏移量10到20处的元素,而真实偏移量10和 11处的元素将被从文档106的活动表示中删除,则构造器线程108修改当前片段描述符的真实偏移属性,以便真实偏移属性是12。这是图4的示例中所示出的情况。
然后,构造器线程108克隆当前索引节点(1508)。在克隆当前索引节点之后,构造器线程108配置克隆的当前索引节点的描述符属性以指示克隆的当前片段描述符(1510)。 然后,构造器线程108设置当前节点指针以指示克隆的当前索引节点(1512)。在设置当前节点指针之后,构造器线程108执行图18中所示出的操作“C”以完成元素删除操作1400。
否则,如果删除的元素是当前片段中的元素中的全部(1502的“是”),则构造器线程108确定当前索引节点是否具有左子节点属性(1514)。如果当前索引节点具有左子节点属性(1514的“是”),则构造器线程108执行图16中所示出的操作“D”,然后执行图18中所示出的操作“C”,以完成元素删除操作1400。
另一方面,如果当前索引节点没有左子节点属性(1514的“否”),则构造器线程 108确定当前索引节点是否具有右子节点属性(1516)。如果构造器线程108确定当前索引节点具有右子节点属性(1518的“是”),则构造器线程108克隆当前索引节点(1518)。在克隆当前索引节点之后,构造器线程108配置克隆的当前索引节点的描述符属性以指示由当前索引节点的右子节点属性所指示的片段描述符(1520)。然后,构造器线程108配置克隆的当前索引节点的右子节点属性以指示没有索引节点(1522)。然后,构造器线程108设置当前节点指针以指示克隆的当前索引节点(1512)。在设置当前节点指针之后,构造器线程 108执行图18中所示出的操作“C”以完成元素删除操作1400。
如果当前索引节点没有右子节点属性(1516的“否”),则构造器线程108使索引节点从堆栈中退栈(1524)。已退栈索引节点是当前索引节点的父节点。然后,构造器线程108 克隆已退栈索引节点(1526)。接下来,构造器线程108配置克隆的已退栈索引节点以便不指示当前索引节点(1528)。以此方式,构造器线程108从文档106的活动表示中删除当前索引节点。然后,构造器线程108设置当前节点指针以指示克隆的已退栈索引节点(1530)。 以此方式,克隆的已退栈索引节点变为“当前”索引节点。然后,构造器线程108执行图18 中所示出的操作“C”以完成元素删除操作1400。
图16是示出了元素删除操作1400的延续1600的流程图。如图16的示例所示, 当构造器线程108克隆当前索引节点时(1602),延续1600开始。接下来,构造器线程108 确定在当前索引节点的左子树中是否只有单个节点(1604)。如果在当前索引节点的左子树中只有单个节点(1604的“是”),则构造器线程108配置克隆的当前索引节点的描述符属性以表示由当前索引节点的左子节点属性所指示的片段描述符(1606)。以此方式,构造器线程108从片段描述符表302的活动版本中删除当前片段描述符。接下来,构造器线程108 配置克隆的当前索引节点的左子节点属性以指示没有其他索引节点(1608)。以此方式,构造器线程108从索引树300的活动版本中删除左子节点属性。
如果在当前索引节点的左子树中有一个以上的索引节点(1604的“否”),则构造器线程108配置克隆的当前索引节点的描述符属性以表示由当前索引节点的左子树中的最右边索引节点所指示的片段描述符(1610)。以此方式,构造器线程108从片段描述符表的活动版本中删除最初当前索引节点所指示的片段描述符。为便于说明,本说明书将当前索引节点的左子树中的最右边索引节点称为“最右边索引节点”。接下来,构造器线程108 克隆当前索引节点下面的最右边索引节点的先辈索引节点(1612)。例如,如果在当前索引节点和最右边索引节点之间在索引树300中有三个索引节点,则构造器线程108克隆这三个索引节点。
在克隆先辈索引节点之后,构造器线程108配置最右边索引节点的父节点的右子节点属性以不指示任何索引节点(1614)。以此方式,从索引树300的活动版本中删除最右边索引节点。然后,构造器线程108连接最右边索引节点的克隆的先辈索引节点(1616)。 例如,如果在当前索引节点和最右边索引节点之间在索引树300中有三个索引节点,则构造器线程108配置这三个索引节点的克隆节点的左或右子节点属性,以使得这三个索引节点的克隆节点具有与这三个索引节点相同的父子关系。
然后,构造器线程108设置当前节点指针以指示克隆的当前索引节点(1618)。在设置当前节点指针之后,构造器线程108执行图18中所示出的操作“C”以完成元素删除操作 1400。
图17是示出了元素删除操作1400的进一步延续1700的流程图。如图17的示例所示,当构造器线程108克隆当前片段描述符时(1702),延续1700开始。如上文所讨论的, 当前片段描述符是由当前索引节点所指示的片段描述符。当构造器线程108克隆当前片段描述符时,构造器线程108生成此处被称为克隆的当前片段描述符的新片段描述符。至少一开始,克隆的当前片段描述符与当前片段描述符具有相同偏移属性和长度属性。接下来, 构造器线程108克隆当前索引节点(1704)。
然后,构造器线程108确定在当前片段中是否有具有大于删除的元素的虚拟偏移量的虚拟偏移量的元素(1706)。如果在当前片段中没有具有大于删除的元素的虚拟偏移量的虚拟偏移量的元素(1706的“否”),则构造器线程108修改克隆的当前片段描述符的长度属性(1708)。构造器线程108修改克隆的当前片段描述符的长度属性,以指示真实元素阵列304的不延伸到最左边的删除的元素的片段。例如,如果当前片段包括具有真实偏移量 10到20的元素,而真实偏移量19和20处的元素将被从文档106的活动表示中删除,则构造器线程108修改克隆的当前片段描述符的长度属性,以便长度属性是9而不是11。在修改克隆的当前片段描述符的长度属性之后,构造器线程108执行图18中所示出的操作“C” 以完成元素删除操作1400。
接下来,构造器线程108配置克隆的当前索引节点的描述符属性以指示克隆的当前片段描述符(1710)。以此方式,克隆的当前片段描述符变为由克隆的当前索引节点所指示的片段描述符。在配置克隆的当前索引节点的描述符属性以指示克隆的当前片段描述符之后,构造器线程108设置当前节点指针以指示克隆的当前索引节点(1712)。然后,构造器线程108执行图18的示例中所示出的操作“C”以完成元素删除操作1400。
否则,如果在当前片段中有一个或多个具有大于删除的元素的虚拟偏移量的虚拟偏移量的元素(1706的“是”),则构造器线程108修改克隆的当前片段描述符的长度属性, 以便克隆的当前片段描述符指示真实元素阵列304的只延长到最左边的删除的元素的片段(1714)。例如,如果当前片段包括具有真实偏移量10到20的元素,而具有真实偏移量15 和16的元素将被从文档106的活动表示中删除,则构造器线程108修改克隆的当前片段描述符的长度属性,以便长度属性是5。
在修改克隆的当前片段描述符的长度属性之后,构造器线程108生成新索引节点 (1716)。如果当前索引节点具有左子节点属性,则构造器线程108配置新索引节点的左子节点属性以指示当前索引节点的左子节点属性(1718)。以此方式,当前索引节点的左子节点属性变为新索引节点的左子节点属性。然后,构造器线程108配置新索引节点的描述符属性以指示克隆的当前片段描述符(1720)。以此方式,克隆的当前片段描述符变为由新的索引节点所指示的片段描述符。
然后,构造器线程108生成新片段描述符(1722)。新片段描述符指示包含是具有大于删除的元素的虚拟偏移量的虚拟偏移量的当前片段的一部分的元素的真实元素阵列304的片段。例如,如果当前片段包括具有真实偏移量10到20的元素并且删除的元素是具有真实偏移量15和16的元素,则新片段描述符具有17的真实偏移属性和4的长度属性。
接下来,构造器线程108配置克隆的当前索引节点的描述符属性以指示新的片段描述符(1724)。然后,构造器线程108配置克隆的当前索引节点的左子节点属性以指示新索引节点(1726)。以此方式,新索引节点变为克隆的当前索引节点的左子节点属性。然后, 构造器线程108重新平衡当前子树(1728)。在重新平衡当前子树之后,构造器线程108设置当前节点指针以指示当前子树的根节点(1730)。然后,构造器线程108执行图18中所示出的操作“C”以完成元素删除操作1400。
图18是示出了元素删除操作1400的进一步延续1800的流程图。如图18的示例所示,当构造器线程108确定堆栈上是否有任何索引节点时(1802),延续1800开始。
如果在堆栈上有任何索引节点(1802的“是”),则构造器线程108使索引节点从堆栈中退栈(1804)。然后,构造器线程108克隆已退栈索引节点(1806)。当构造器线程108 克隆已退栈索引节点时,构造器线程108生成此处被称为克隆的已退栈索引节点的新索引节点。当构造器线程108克隆已退栈索引节点时,克隆的已退栈索引节点的左子节点属性、 右子节点属性,以及描述符属性与已退栈索引节点的左子节点属性、右子节点属性,以及描述符属性具有相同值。
在克隆已退栈索引节点之后,构造器线程108确定与已退栈索引节点相关联的片段的虚拟偏移量是否小于与当前索引节点相关联的片段的虚拟偏移量(1808)。如果与已退栈索引节点相关联的片段的虚拟偏移量小于与当前索引节点相关联的片段的虚拟偏移量 (1808的“是”),则构造器线程108设置克隆的已退栈索引节点的左子节点属性以指示当前索引节点(1810)。以此方式,当前节点变为克隆的已退栈索引节点的左子节点属性。
否则,如果与已退栈索引节点相关联的片段的虚拟偏移量不小于(S卩,大于)与当前索引节点相关联的片段的虚拟偏移量(1808的“否”),则构造器线程108设置克隆的已退栈索引节点的右子节点属性以表示当前索引节点(1812)。以此方式,当前索引节点变为克隆的已退栈索引节点的右子节点属性。
在设置克隆的已退栈索引节点的左或右子节点属性之后,构造器线程108设置当前节点指针,以指示克隆的已退栈索引节点(1814)。以此方式,克隆的已退栈索引节点变为“当前”索引节点。在设置当前节点指针以指示克隆的已退栈索引节点之后,构造器线程 108再次确定堆栈上是否有任何索引节点(1802)。如果在堆栈上有索引节点,则构造器线程108重复步骤1804、1806、1808、1810或1812、1814,以及1816。否则,如果在堆栈上没有索引节点,则构造器线程108设置当前树指针以指示当前索引节点(1818)。在设置当前树指针以指示当前索引节点之后,元素删除操作1400完成。此外,在构造器线程108设置当前树指针之后,文档106的活动表示变为文档106的最近可用的非活动表示。
图19是示出了读取器线程IlOA的示例操作1900的流程图。虽然操作1900是参考读取器线程IlOA来描述的,但是,操作1900可以由读取器线程110中的任何一个来执行。
当应用104唤醒读取器线程IlOA时,读取器线程IlOA的操作1900开始。当读取器线程IlOA醒来时,读取器线程IlOA确定是否存在当前非活动的索引树(1902)。当前非活动的索引树是由当前树指针所表示的索引树。由于当前树指针表示索引树的最近的可用的非活动版本,因此,当前索引树是索引树的最近可用的非活动版本。读取器线程IlOA确定当当前树指针包含空值时当前索引树不存在。如果当前索引树不存在(1904的“否”),则读取器线程IlOA随后再次确定当前索引树是否存在(1904)。读取器线程IlOA持续确定当前索引树是否存在,直到当前索引树存在。
如果读取器线程IlOA确定当前索引树存在(1904的“是”),则读取器线程IlOA 确定当前索引树是否具有根索引节点(1906)。在某些实施例中,当前索引树是可以包含索引节点的软件对象。在这样的实施例中,当这样的软件对象被实例化时,当前索引树可以存在,不管软件对象是否包含任何索引节点。如果当前索引树没有根索引节点(1906的 “否”),则读取器线程IlOA随后再次确定当前索引树是否具有根索引节点(1906)。读取器线程11OA持续确定当前索引树是否具有根索引节点,直到当前索引树具有根索引节点。
如果当前索引树有根索引节点,则读取器线程IlOA设置读取指针以指示当前索引树的根索引节点(1908)。如此处所使用的,根读取节点是由读取指针所表示的索引节点。 然后,读取器线程IlOA执行读取索引树中的索引节点的深度优先遍历(1910)。读取索引树是其根读取节点是根的索引树。随着读取器线程IlOA遍历读取索引树中的索引节点,读取器线程IlOA可以对与索引节点相关联的元素执行各种动作。例如,读取器线程IlOA可以执行拼写检查操作,该操作检查与索引节点相关联的元素中的单词的拼写。在另一示例中, 读取器线程IlOA可以基于与索引节点相关联的元素中的单词来更新搜索索引。在再一个示例中,读取器线程IIOA可以将元素写入到(例如,保存)到本地或远程存储位置。由于读取器线程IlOA可以与构造器线程108并发地操作,因此,用户102可能不会感觉到由于读取器线程IlOA的操作所造成的构造器线程108的性能的任何延迟或速度减慢。
在执行读取索引树中的索引节点的完整的遍历之后,读取器线程IlOA确定读取器线程IlOA的操作是否完成(1912)。如果读取器线程IlOA的操作完成(1912的“是”),则读取器线程IlOA休眠(1914)。
否则,如果读取器线程IlOA的操作未完成(1912的“否”),则读取器线程IlOA设置读取指针以指示当前索引树的根索引节点(1908)。随着读取器线程IlOA遍历读取索引树中的索引节点,构造器线程108可以并发地执行,执行元素插入和/或元素删除操作。由于构造器线程108不会改变读取索引树中的任何索引节点的属性,因此,确保了来自读取索引树的读取操作的逻辑一致性。然而,构造器线程108可以更新当前树指针以表示另一索引树。因此,当读取器线程IlOA设置读取指针以指示当前索引树的根索引节点时,当前索引树可以是与读取器线程IlOA刚刚遍历的读取索引树不同的索引树。以此方式,读取器线程IlOA开始遍历最当前的索引树。
图20是示出了示例计算设备2000的框图。在一些实施例中,计算系统100是使用类似计算设备2000的一个或多个计算设备来实现的。应当理解,在其他实施例中,计算系统100是使用还具有除了图20的示例所示的硬件组件之外的硬件组件的计算设备来实现的。
计算系统是包括一个或多个计算设备的系统。计算设备是能够处理信息的物理设备。计算设备的示例类型包括台式计算机、膝上型计算机、独立服务器计算机、刀片式服务器计算机、移动电话、个人媒体播放器、视频游戏控制台、集成到车辆中的计算机、电视机机顶盒、中间网络设备,及其他类型的能够处理信息的物理设备。
在不同的实施例中,计算设备是以不同的方式实现的。例如,在图20的示例中,计算设备2000包括存储器2002、处理系统2004、辅助存储设备2006、网络接口卡2008、视频接口 2010、显示设备2012、外部组件接口 2014、外部存储设备2016、输入设备2018、打印机 2020、以及通信介质2022。在其他实施例中,计算设备是使用多一些或少一些的硬件组件来实现的。例如,在另一示例实施例中,计算设备不包括视频接口、显示设备、外部存储设备或输入设备。
存储器2002是数据存储系统。数据存储系统是包括一个或多个计算机可读数据存储介质的系统。计算机可读数据存储介质是存储可由计算设备读取的数据和/或计算机可执行指令的有形的设备或制品。在不同的实施例中,存储器2002是以不同的方式实现的。例如,在各实施例中,存储器2002是使用各种类型的计算机可读数据存储介质来实现的。计算机可读数据存储介质示例类型包括,但不仅限于,动态随机存取存储器(DRAM)、 双倍数据速率同步动态随机存取存储器(DDR SDRAM)、延迟缩短的DRAM、DDR2 SDRAM、 DDR3SDRAM、Rambus RAM、固态存储器、闪存、只读存储器(ROM)、电可擦可编程只读存储器, 及其他类型的存储数据的设备和/或制品。
处理系统2004是包括一个或多个处理单元的系统。处理单元包括有选择地执行软件指令的一个或多个物理集成电路。在各实施例中,处理系统2004是以各种方式实现的。例如,在一个示例实施例中,处理系统2004被实现为一个或多个处理核。例如,在此示例实施例中,处理系统2004可以被实现为一个或多个Intel Core 2微处理器。在另一不例实施例中,处理系统2004被实现为一个或多个单独的微处理器。在再一个示例实施例中, 处理系统2004被实现为提供专用功能的ASIC。在再一个示例实施例中,处理系统2004通过使用ASIC并通过执行软件指令来提供专用功能。
在不同的实施例中,处理系统2004执行不同的指令集中的软件指令。例如,在各实施例中,处理系统2004执行诸如x86指令集、POWER指令集、RISC指令集、SPARC指令集、 IA-64指令集、MIPS指令集之类的指令集和/或其他指令集中的软件指令。
辅助存储设备2006包括一个或多个计算机可读数据存储介质。辅助存储设备 2006存储不能被处理系统2004直接访问的数据和软件指令。换言之,处理系统2004执行输入/输出操作以从辅助存储设备2006检索数据和/或软件指令。在各实施例中,辅助存储设备2006是通过各种类型的计算机可读数据存储介质来实现的。例如,辅助存储器设备 2006可以通过一个或多个磁盘、磁带驱动器、⑶-ROM光盘、DVD-ROM光盘、蓝光光盘、固态存储设备、Bernoulli盒式磁带,和/或其他类型的计算机可读取的数据存储介质来实现。
网络接口卡2008使计算设备2000能从计算机通信网络接收数据并向其发送数据。在不同的实施例中,网络接口卡2008是以不同的方式实现的。例如,在各实施例中, 网络接口卡2008被实现为以太网接口、令牌环网络接口、光纤网络接口、无线网络接口(例如,WiFi、WiMax等等),或另一种类型的网络接口。
视频接口 2010使计算设备2000能向显示设备2012输出视频信息。在不同的实施例中,视频接口 2010是以不同的方式实现的。例如,在一个示例实施例中,视频接口 2010被集成到计算设备2000的主板中。在另一示例实施例中,视频接口 2010是视频扩展卡。示例类型的视频扩展卡包括由安大略省马克姆市的ATI Technologies有限公司制造的Radeon 图形卡、由加利福尼亚州圣克拉拉市的Nvidia (英伟达)公司制造的Geforce图形卡和其他类型的图形卡。
在各实施例中,显示设备2012被实现为各种类型的显示设备。显示设备的示例类型包括,但不仅限于,阴极射线管显示器、LCD显示面板、等离子屏幕显示面板、触敏显示面板、LED屏幕、投影仪,及其他类型的显示设备。在各实施例中,视频接口 2010以各种方式与显示设备2012通信。例如,在各实施例中,视频接口 2010通过通用串行总线(USB)连接器、VGA连接器、数字可视接口(DVI)连接器、S-Video (S视频)连接器、高清晰度多媒体接口(HDMI)接口、DisplayPort (显示端口)连接器,或其他类型的连接器来与显示设备2012 进行通信。
外部组件接口 2014使计算设备2000能与外部设备进行通信。在各实施例中,外部组件接口 2014是以不同的方式实现的。例如,在一个示例实施例中,外部组件接口 2014 是USB接口。在其他示例实施例中,计算设备2000是FireWire (火线)接口、串行端口接口、并行端口接口、PS/2接口,和/或使计算设备2000能与外部组件进行通信的另一种类型的接口。
在不同的实施例中,外部组件接口 2014使计算组件2000能与不同的外部组件进行通信。例如,在图20的示例中,外部组件接口 2014使计算设备2000能与外部存储设备 2016、输入设备2018,以及打印机2020进行通信。在其他实施例中,外部组件接口 2014使计算组件2000能与多一些或少一些的外部组件进行通信。外部组件的其他示例类型包括, 但不仅限于,扬声器、电话充电插孔、调制解调器、媒体播放器对接器,其他计算设备、扫描仪、数码相机、指纹读取器、及其他可以连接到计算设备2000的设备。
外部存储设备2016是包括一个或多个计算机可读数据存储介质的外部组件。计算设备2000的不同的实现与不同类型的外部存储设备进行连接。外部存储设备的示例类型包括,但不仅限于,磁带驱动器、闪存模块、磁盘驱动器、光盘驱动器、闪存单元、zip磁盘驱动器、光学点播机、及其他类型的包括一个或多个计算机可读数据存储介质的设备。输入设备2018是向计算设备2000的提供用户输入的外部组件。计算设备2000的不同的实现与不同类型的输入设备进行连接。输入设备的示例类型包括,但不仅限于,键盘、鼠标、轨迹球、指示笔输入设备、键盘、话筒、游戏杆、触敏显示屏幕,及其他类型的向计算设备2000提供用户输入的设备。打印机2020是向纸张打印数据的外部设备。计算设备2000的不同的实现与不同类型的打印机进行连接。打印机的示例类型包括,但不仅限于,激光打印机、喷墨打印机、照片打印机、复印机、传真机、收据打印机、点阵打印机,或其他类型的向纸张打印数据的设备。
通信介质2022促进计算设备2000的硬件组件之间的通信。在不同的实施例中, 通信介质2022促进计算设备2000的不同的组件之间的通信。例如,在图20的示例中,通信介质2022促进存储器2002、处理系统2004、辅助存储设备2006、网络接口卡2008、视频接口 2010,以及外部组件接口 2014之间的通信。在计算设备2000的不同的实现中,通信介质2022是以不同的方式实现的。例如,在计算设备2000的不同的实现中,通信介质2022 可以被实现为PCI总线、PCI Express总线、加速图形端口 (AGP)总线、Infiniband互连、 串行高级技术附接(ATA)互连、并行ATA互连、光纤信道互连、USB总线,小型计算系统接口 (SCSI)接口,或另一种类型的通信介质。
存储器2002存储各种类型的数据和/或软件指令。例如,在图20的示例中,存储器2002存储基本输入/输出系统(BIOS)2024、操作系统2026、应用软件2028,以及程序数据2030。BIOS 2024包括一组软件指令,这些软件指令,在由处理系统2004执行时,导致计算设备2000启动。操作系统2026包括一组软件指令,这些软件指令,在由处理系统2004执行时,导致计算设备2000提供协调计算设备2000的活动和资源共享的操作系统。操作系统的示例类型包括,但不仅限于,MICROSOFT WINDOWS 、Linux、Unix、Apple OSX, Apple OS X iPhone、Palm web0S、Palm OS、Google Chrome OS、Google Android OS,等等。 应用软件1928包括一组软件指令,这些软件指令,在由处理系统2004执行时,导致计算设备2000向计算设备2000的用户提供应用。程序数据2030是由应用软件2028所生成的和 /或使用的数据。
上文所描述的各实施例是只作为说明来提供的,并且不应该被解释为限制。本领域的技术人员将轻松地认识到,在不遵循此处所示出和描述的示例实施例和应用的情况下可以进行各种修改和更改。例如,各实施例是参考文档描述的。然而,其他实施例将本说明书中所描述的技术应用到其他类型的分级数据结构。此外,图形所示出的操作只是示例。在各实施例中,类似的操作可包括比图形中所示出的那些多一些或少一些的步骤。此外,在其他实施例中,类似的操作可包括图形中所示出的操作的不同的顺序的步骤。
权利要求
1.一种用于对文档执行操作的方法,所述方法包括提供包括一个或多个处理单元和存储器的计算系统;由所述计算系统执行通过修改所述文档的活动表示来修改所述文档的构造器线程,所述文档的所述活动表示存储在所述存储器中;以及由所述计算系统与所述构造器线程并发地执行读取器线程,所述读取器线程使用所述文档的非活动表示来对所述文档执行操作,所述文档的非活动表示存储在所述存储器中, 所述文档的活动表示和所述文档的非活动表示不包括相同数据在所述存储器中的不同副本,其中,当读取所述文档的非活动表示中的数据时,确保逻辑一致性,而不锁定所述文档的非活动表示中的任何数据。
2.如权利要求I所述的方法,其特征在于由所述读取器线程执行的操作不修改所述文档;每当所述构造器线程接收到修改所述文档的输入时,所述构造器线程执行创建所述文档的新表示的操作;并且在所述构造器线程完成所述操作之后,所述文档的所述新表示可供所述读取器线程使用。
3.如权利要求I所述的方法,其特征在于所述文档是文字处理文档;并且所述方法还包括由所述计算系统执行文字处理应用,所述文字处理应用使用户能与所述文档进行交互,所述文字处理应用唤醒所述构造器线程和所述读取器线程。
4.如权利要求I所述的方法,其特征在于所述文档在内部被表示为文档树,所述文档树是文档元素的层次结构;所述文档的活动表示包括真实元素阵列,所述真实元素阵列包含表示所述文档树中的每一个文档元素的元素;所述文档的非活动表示包括所述真实元素阵列;并且所述文档的活动表示和所述文档的非活动表示不包括所述真实元素阵列中的相同元素在所述存储器中的不同副本。
5.如权利要求4所述的方法,其特征在于,所述构造器线程在所述读取器线程并发地从所述文档的非活动表示中读取给定元素时从所述文档的活动表示中删除所述给定元素, 所述给定元素表示所述文档树中的相同文档元素。
6.如权利要求4所述的方法,其特征在于所述文档的活动表示包括索引树的活动版本和片段描述符表的活动版本,所述片段描述符表包括一组片段描述符,所述片段描述符中的每一个都标识所述真实元素阵列中的一个片段,所述索引树包括索引节点的层次结构,所述索引节点中的每一个都指示所述片段描述符中的一个;所述文档的非活动表示包括所述索引树的非活动版本和所述片段描述符表的非活动版本;对于所述索引树中的每一个索引节点,与所述索引节点的左子树中的索引节点相关联的元素具有小于与所述索引节点相关联的元素的虚拟偏移量的虚拟偏移量,与所述索引节点的右子树中的索引节点相关联的元素具有大于与所述索引节点相关联的元素的虚拟偏移量的虚拟偏移量,所述虚拟偏移量是与虚拟元素阵列的开始处的偏移量,所述虚拟元素阵列是所述文档树的一维表示;并且所述文档的活动表示和所述文档的非活动表示在所述存储器中没有所述片段描述符表中的相同片段描述符或所述索引树中的相同索引节点的不同副本。
7.如权利要求6所述的方法,其特征在于为了修改所述文档以包括附加文档元素,所述构造器线程执行元素插入操作,所述元素插入操作通过将一个或多个新元素插入到所述真实元素阵列中,将新片段描述符添加到所述片段描述符表,以及将一个或多个新索引节点添加到所述索引树,来生成所述文档的所述活动表示,所述一个或多个新元素表示所述附加文档元素;在所述构造器线程完成所述元素插入操作之后,所述文档的所述活动表示变得可供所述读取器线程使用。
8.一种计算系统,包括包括多个处理单元的的处理系统;以及种包括计算机可执行指令的存储器,所述计算机可执行指令在由所述处理系统执行时,导致所述计算系统执行通过修改所述文档的活动表示来修改所述文档的构造器线程,所述文档的活动表示存储在所述存储器中;以及与所述构造器线程并发地执行读取器线程,所述读取器线程使用所述文档的非活动表示来对所述文档执行操作,所述文档的非活动表示存储在所述存储器中,所述文档的活动表示和所述文档的非活动表示不包括相同数据在所述存储器中的不同副本,其中,当读取所述文档的非活动表示中的数据时,确保逻辑一致性,而不锁定所述文档的非活动表示中的任何数据,所述读取器线程的操作不修改所述文档。
9.如权利要求8所述的计算系统,其特征在于所述文档在内部被表示为文档树,所述文档树是文档元素的层次结构;所述文档的活动表示包括真实元素阵列,所述真实元素阵列包含表示所述文档树中的每一个文档元素的元素;所述文档的非活动表示包括所述真实元素阵列,所述文档的活动表示和所述文档的非活动表示不包括所述真实元素阵列中的相同元素在所述存储器中的不同副本;所述文档的活动表示包括索引树的活动版本和片段描述符表的活动版本,所述片段描述符表包括一组片段描述符,所述片段描述符中的每一个都标识所述真实元素阵列中的一个片段,所述索引树包括索引节点的层次结构,所述索引节点中的每一个都指示所述片段描述符中的一个;所述文档的非活动表示包括所述索引树的非活动版本和所述片段描述符表的非活动版本;对于所述索引树中的每一个索引节点,与所述索引节点的左子树中的索引节点相关联的元素具有小于与所述索引节点相关联的元素的虚拟偏移量的虚拟偏移量,与所述索引节点的右子树中的索引节点相关联的元素具有大于与所述索引节点相关联的元素的虚拟偏移量的虚拟偏移量,所述虚拟偏移量是与虚拟元素阵列的开始处的偏移量,所述虚拟元素阵列是所述文档树的一维表示;并且所述文档的活动表示和所述文档的非活动表示在所述存储器中没有所述片段描述符表中的相同片段描述符或所述索引树中的相同索引节点的不同副本。
10. 一种存储计算机可读指令的数据存储介质,所述计算机可读指令在被执行时,导致计算系统执行使用户能与文档进行交互的应用,所述文档在内部被表示为文档树,所述文档树包括文档元素的层次结构,所述应用唤醒构造器线程和读取器线程;执行所述构造器线程,所述构造器线程通过修改所述文档的活动表示来修改所述文档,所述文档的活动表示存储在存储器中,所述文档的活动表示包括索引树的活动版本,片段描述符表的活动版本,以及真实元素阵列,所述真实元素阵列包含表示所述文档树中的每一个文档元素的元素,所述片段描述符表包括一组片段描述符,所述片段描述符中的每一个都标识所述真实元素阵列的一个片段,所述索引树包括索引节点的层次结构,所述索引节点中的每一个都指示所述片段描述符中的一个;以及与所述构造器线程并发地执行所述读取器线程,所述读取器线程使用所述文档的非活动表示来对所述文档执行操作,所述文档的非活动表示包括所述索引树的非活动版本, 所述片段描述符表的非活动版本,以及所述真实元素阵列,所述文档的所述非活动表示存储在所述存储器中,所述文档的活动表示和所述文档的非活动表示不包括相同数据在所述存储器中的不同副本,其中,当读取所述文档的非活动表示中的数据时,确保逻辑一致性, 而不锁定所述文档的非活动表示中的任何数据,所述读取器线程的所述操作不修改所述文档,其中,对于所述索引树中的每一个索引节点,与所述索引节点的左子树中的索引节点相关联的元素具有小于与所述索引节点相关联的元素的虚拟偏移量的虚拟偏移量,与所述索引节点的右子树中的索引节点相关联的元素具有大于与所述索引节点相关联的元素的虚拟偏移量的虚拟偏移量,所述虚拟偏移量是与虚拟元素阵列的开始处的偏移量,所述虚拟元素阵列是所述文档树的一维表示。
全文摘要
一种计算系统并发地执行生成器线程和读取器线程。构造器线程通过修改文档的活动表示来修改文档。读取器线程使用文档的非活动表示来对文档执行操作。文档的活动表示和文档的非活动表示存储在计算系统的存储器中。文档的活动表示和文档的非活动表示不包括相同数据在存储器中的不同副本。当读取文档的非活动表示中的数据时,确保逻辑一致性,而不锁定文档的非活动表示中的任何数据。
文档编号G06F9/06GK102939581SQ201180025941
公开日2013年2月20日 申请日期2011年5月16日 优先权日2010年5月27日
发明者C·W·派克 申请人:微软公司
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1