(57)【要約】【課題】  同時実行性Ｂツリーアルゴリズムの効率を高めるための方法を提供すること。【解決手段】  情報管理システムは、コンピュータと、ディスクブロックに関連付けられた複数のノード、およびノード内に記憶されたハンドルを備えるＢツリーデータ構造を含むデータベースとを備える。１つの左リンクハンドルｈｌｅｆｔが、そのノードの左兄弟への各ノード点内に記憶される。キーｋに対してルックアップ動作を行う機構は、Ｂツリーをトラバースし、ノードの左リンクハンドルを参照し、キーｋが、そのノード内に記憶された値ｋｍｉｎ以下である場合に、そのノードの左兄弟にアクセスする。挿入動作および削除動作を行うための機構もまた提供され、ルックアップ動作、挿入動作、削除動作は、インデックスノードＡのキー範囲に、その動作が突き止めようとしているキーｋが含まれないかどうか検出し、ｋ≦Ａ．ｋｍｉｎのとき左兄弟へのハンドルＡ．ｈｌｅｆｔに従う。【選択図】  図４
2004185617.tif 000002
【特許請求の範囲】
【請求項１】
コンピュータと、前記コンピュータに動作可能に接続されたデータベースとを備える情報管理システムであって、
前記データベースは、ディスクブロックに関連付けられた複数のノードと、前記ノード内に記憶されたハンドルとを備えるＢツリーデータ構造を含み、少なくとも１つの左リンクハンドルｈｌｅｆｔが、そのノードの左兄弟への各ノード点内に記憶されることを特徴とするシステム。
【請求項２】
キーｋに対してルックアップ動作を行う機構をさらに備え、前記Ｂツリーをトラバースする際に、前記ルックアップ動作は、所与のノード部で、そのノードの前記左リンクハンドルｈｌｅｆｔを参照し、前記キーｋが、前記ノード内に記憶された値ｋｍｉｎ以下である場合に、前記ノードの左兄弟にアクセスすることを特徴とする請求項１に記載の情報管理システム。
【請求項３】
挿入動作を行う機構をさらに備えることを特徴とする請求項２に記載の情報管理システム。
【請求項４】
前記挿入動作は、インデックスノードＡのキー範囲に、前記動作が突き止めようとしている前記キーｋが含まれないかどうか検出し、前記挿入動作は、ｋ≦Ａ．ｋｍｉｎのとき前記左兄弟へのハンドルＡ．ｈｌｅｆｔに従うことを特徴とする請求項３に記載の情報管理システム。
【請求項５】
削除動作を行う機構をさらに備えることを特徴とする請求項２に記載の情報管理システム。
【請求項６】
前記削除動作は、インデックスノードＡのキー範囲に、前記動作が突き止めようとしている前記キーｋが含まれないかどうか検出し、前記動作は、ｋ≦Ａ．ｋｍｉｎのとき前記左兄弟へのハンドルＡ．ｈｌｅｆｔに従うことを特徴とする請求項５に記載の情報管理システム。
【請求項７】
挿入動作および削除動作を行う機構をさらに備え、前記ルックアップ動作、挿入動作、削除動作は、インデックスノードＡのキー範囲に、前記動作が突き止めようとしている前記キーｋが含まれないかどうか検出し、前記動作は、ｋ≦Ａ．ｋｍｉｎのとき前記左兄弟へのハンドルＡ．ｈｌｅｆｔに従うことを特徴とする請求項２に記載の情報管理システム。
【請求項８】
前記Ｂツリーデータ構造は、<hleft, kmin, h0, k0, h1, k1, ..., hn-1, kn-1, hn, kmax, hright>という構造を有する少なくとも１つのインデックスノードを備え、ただし、ｈｌｅｆｔは左兄弟のハンドルであり、残りのデータ要素（kmin, h0, k0, h1, k1, ..., hn-1, kn-1, hn, kmax, hright）は、Ｂ−リンクツリーデータ構造によるハンドルおよびキーであることを特徴とする請求項１に記載の情報管理システム。
【請求項９】
ディスクブロックに関連付けられた複数のノードと、前記ノード内に記憶されたハンドルとを備え、少なくとも１つの左リンクハンドルｈｌｅｆｔが、そのノードの左兄弟への各ノード点内に記憶される、コンピュータ可読媒体上で記憶されるＢツリーデータ構造。
【請求項１０】
<hleft, kmin, h0, k0, h1, k1, ..., hn-1, kn-1, hn, kmax, hright>という構造を有する少なくとも１つのインデックスノードを備え、ただし、ｈｌｅｆｔは左兄弟のハンドルであり、残りのデータ要素（kmin, h0, k0, h1, k1, ..., hn-1, kn-1, hn, kmax, hright）は、Ｂ−リンクツリーデータ構造によるハンドルおよびキーであることを特徴とする請求項９に記載のデータ構造。
【請求項１１】
複数のノードと、前記ノード内に記憶されたハンドルとを備えるデータ構造を維持することを含む、コンピュータによって実施される方法であって、少なくとも１つの左リンクハンドルｈｌｅｆｔが、そのノードの左兄弟への各ノード点内に記憶される方法。
【請求項１２】
前記方法は、キーｋに対してルックアップ動作を行うことをさらに含み、前記ルックアップ動作は、前記データ構造をトラバースすること、および、所与のノード部で、そのノードの前記左リンクハンドルｈｌｅｆｔを参照し、前記キーｋが、前記ノード内に記憶された値ｋｍｉｎ以下である場合に、前記ノードの左兄弟にアクセスすることを含むことを特徴とする請求項１１に記載の方法。
【請求項１３】
挿入動作を行うことをさらに含むことを特徴とする請求項１２に記載の方法。
【請求項１４】
前記挿入動作は、インデックスノードＡのキー範囲に、前記動作が突き止めようとしている前記キーｋが含まれないかどうか検出し、前記動作は、ｋ≦Ａ．ｋｍｉｎのとき前記左兄弟へのハンドルＡ．ｈｌｅｆｔに従うことを特徴とする請求項１３に記載の方法。
【請求項１５】
削除動作を行う機構をさらに備えることを特徴とする請求項１２に記載の方法。
【請求項１６】
前記削除動作は、インデックスノードＡのキー範囲に、前記動作が突き止めようとしている前記キーｋが含まれないかどうか検出し、前記動作は、ｋ≦Ａ．ｋｍｉｎのとき前記左兄弟へのハンドルＡ．ｈｌｅｆｔに従うことを特徴とする請求項１５に記載の方法。
【請求項１７】
挿入動作および削除動作を行うことをさらに含み、前記ルックアップ動作、挿入動作、削除動作は、インデックスノードＡのキー範囲に、前記動作が突き止めようとしている前記キーｋが含まれないかどうか検出し、前記動作は、ｋ≦Ａ．ｋｍｉｎのとき前記左兄弟へのハンドルＡ．ｈｌｅｆｔに従うことを特徴とする請求項１２に記載の方法。
【請求項１８】
前記データ構造は、<hleft, kmin, h0, k0, h1, k1, ..., hn-1, kn-1, hn, kmax, hright>という構造を有する少なくとも１つのインデックスノードを備え、ただし、ｈｌｅｆｔは左兄弟のハンドルであり、残りのデータ要素（kmin, h0, k0, h1, k1, ..., hn-1, kn-1, hn, kmax, hright）は、Ｂ−リンクツリーデータ構造によるハンドルおよびキーであることを特徴とする請求項１１に記載の方法。
【発明の詳細な説明】
【技術分野】
【０００１】
本発明は一般に、それだけには限らないが、データベース管理システムおよびファイルシステムを含む、データを記憶し、編成し、取り出す情報管理システム（情報検索システムとも呼ばれることがある）の分野に関し、より詳細には、そのようなシステム内で使用するための新規なデータ構造およびアルゴリズムに関する。本発明は、それだけには決して限らないが、特に、Ｂツリーデータ構造およびその変形形態、ならびにＳＱＬタイプのデータベースと共に使用するのに適している。
【背景技術】
【０００２】
Ｂツリーは、リレーショナルデータベースおよび非リレーショナルデータベースに対する、またさらに、大量のデータをインデックスしそれにアクセスするための方法として１組のリンクされたノードを含むデータ構造が使用されるファイルシステムおよび他のシステムに対するコア技術である。データベース管理システムは、本発明が適している種類の情報管理／検索システムの一例である。しかし、本発明は、それだけには決して限らないが、データベースと共に使用するのに十分適しているため、本発明の背景と例示的な実施形態について、データベースを参照して述べることにする。
【０００３】
最小限のロックを有する同時実行性Ｂツリー（ｃｏｎｃｕｒｒｅｎｔ  Ｂ−Ｔｒｅｅ）は、分散データベースを構築するための手段となり、単一の関係が複数のマシンに跨ることができる。複数のマシンにわたって関係を分散することにより、スケーラブルなデータベースを構築することが可能になり、データベースのサイズは、さらにハードウェアを追加することによって簡単に増大することができる。
【０００４】
【非特許文献１】R. Bayer and E. McCreight. Organization and Maintenance of Large Ordered Indexes. Acta Informatica, 1(3):173-189, 1972
【非特許文献２】D. Comer. The Ubiquitous Ｂツリー. ACM Computing Surveys, 11(2):121-128, June 1979
【非特許文献３】P.L. Lehman and S.B. Yao. Efficient Locking for Concurrent Operations on Ｂツリーs. ACM Transactions on Information retrieval systems, 6(4):650-670, December 1981
【非特許文献４】Yehoshua Sagiv. Concurrent Operations on Ｂツリーs with Overtaking. Journal of Computer and System Sciences, Vol. 3, No. 2, Oct. 1986.
【非特許文献５】Paul Wang. An In-Depth Analysis of Concurrent Ｂツリー Algorithms. Technical report MIT/LCS/TR-496, Laboratory for Computer Science, Massachusetts Institute of Technology, Feb. 1991.
【非特許文献６】H. Wedekind. On the selection of access paths in an information retrieval system. In J.W. Klimbie and K.L. Koffman, editors, Database Management, pages 385-397. North Holland Publishing Company, 1974.
【発明の開示】
【発明が解決しようとする課題】
【０００５】
本発明は、特に、同時実行性Ｂツリーアルゴリズムの効率を高めるための方法に関する。
【課題を解決するための手段】
【０００６】
以下でより詳しく論じるように、本明細書で開示されている主題は、（ａ）ロック動作の強引な最小限化により現況技術で発生する可能性のある、Ｂツリー動作がツリーの中で「迷子」になることを防止する追加データを維持すること、（ｂ）余分な同期を必要とすることなしに削除済みノードをガーベッジコレクションすること（現況技術のアルゴリズムは、ガーベッジコレクションのためにタイムスタンプをベースとする手法を使用し、残りのＢツリー動作すべての開始時間を追跡するために余分な同期を必要とする）を対象とする。
【０００７】
Ｂツリーについての他の背景情報は、文書に見出すことができる（たとえば、非特許文献１、２、３、４、５、６参照）。
【０００８】
本発明の第１の態様による情報管理システムは、コンピュータとデータベースとを含み、データベースは、ディスクブロック（または、より一般的には、本発明がディスク以外の記憶媒体と共に使用される場合「記憶ブロック」）に関連付けられた複数のノードと、ノード内に記憶されたハンドルと（任意選択で、ハンドルおよびノードのそれぞれに関連付けられたバージョン番号と）をそれぞれが備える１つまたは複数のＢツリーデータ構造を備える。少なくとも１つの左リンクハンドルｈｌｅｆｔが、各ノード点内で、そのノードの左兄弟（ｌｅｆｔ  ｓｉｂｌｉｎｇ）に記憶される。キーｋに対してルックアップ動作を行う機構は、Ｂツリーをトラバースし、ノードの左リンクハンドルｈｌｅｆｔを参照し、キーｋが、ノード内に記憶された値ｋｍｉｎ以下である場合に、ノードの左兄弟にアクセスする。挿入動作および削除動作を行うための機構もまた提供され、ルックアップ動作、挿入動作、削除動作は、インデックスノードＡのキー範囲が、その動作が突き止めようとしているキーｋを含まないかどうか検出し、ｋ≦Ａ．ｋｍｉｎのとき左兄弟へのハンドルＡ．ｈｌｅｆｔに従う。
【０００９】
「ノード」は、複数のディスクまたは記憶ブロックに跨ることができること、リンクおよびバージョン番号は、個々のディスクブロックではなくノードに論理的に関連付けることができることに留意されたい。
【００１０】
本発明のこれらや他の特徴について、以下で述べる。
【発明を実施するための最良の形態】
【００１１】
以下、本発明の現在好ましい実施について述べる。最初に、セクションＡでは、主に、本発明を多種多様な方法、たとえば、コンピュータ可読媒体に記憶されたデータ構造、および／または汎用コンピュータ上で実行されるソフトウェアをベースとするプロセスで実施することができることを示すために、図１を参照しながら例示的なコンピューティング環境について述べる。Ｂツリーアルゴリズムは、コードと、このコードが操作するデータ構造という２つの基本的なものを必要とすることは周知である。コードは、プロセス内またはファームウェア内を含む様々な所で実施することができる。データは、（たとえば、ＲＡＭ、ディスク、取外し式媒体など、持続度の異なる）どこにでも保持することができる。この説明に続いて、セクションＢでは、本明細書で開示されている本発明のデータ構造および方法の２つの主な態様について概要を提供する。これら２つの主な態様は、（１）削除および圧縮動作を容易にするバージョン付きノードと、（２）ツリーのトラバース動作を容易にする左リンクとを含む。セクションＣからＦは、本発明を実施することができる例示的な方法のさらなる詳細について述べる。最後に、セクションＧは、結論を提供する。  
【００１２】
Ａ．例示的なコンピューティング環境
図１は、本発明を実施することができる好適なコンピューティングシステム環境１００の一例を示す。コンピューティングシステム環境１００は、好適なコンピューティング環境の一例にすぎず、本発明の使用または機能の範囲についてどんな制限も暗示しないものとする。コンピューティング環境１００は、例示的な動作環境１００に示されている構成要素のいずれか１つまたは組合せに関してどんな依存性も要件も有すると解釈すべきでない。
【００１３】
本発明は、多数の他の汎用または専用コンピューティングシステム環境または構成と共に動作可能である。本発明と共に使用するのに適している可能性のある周知のコンピューティングシステム、環境、および／または構成の例には、それだけには限らないが、パーソナルコンピュータ、サーバコンピュータ、ハンドヘルドデバイスまたはラップトップデバイス、マルチプロセッサシステム、マイクロプロセッサをベースとするシステム、ディスクコントローラ、セットトップボックス、プログラム可能な家電、ネットワークＰＣ、ミニコンピュータ、メインフレームコンピュータ、上記のシステムまたはデバイスのいずれかを含む分散コンピューティング環境などが含まれる。
【００１４】
本発明について、コンピュータによって実行される、プログラムモジュールなどコンピュータ実行可能命令の全体的な状況で述べる。一般に、プログラムモジュールは、特定のタスクを実行する、あるいは特定の抽象データタイプを実施するルーチン、プログラム、オブジェクト、コンポーネント、データ構造などを含む。本発明はまた、通信ネットワークまたは他のデータ転送媒体を介してリンクされた遠隔処理デバイスによってタスクが実行される分散コンピューティング環境内で実施することができる。分散コンピューティング環境では、プログラムモジュールや他のデータは、メモリ記憶装置を含むローカルと遠隔双方のコンピュータ記憶媒体内に位置する可能性がある。
【００１５】
図１を参照すると、本発明を実施するための例示的なシステムが、コンピュータ１１０の形態で汎用コンピューティングデバイスを含む。コンピュータ１１０の構成要素には、それだけには限らないが、処理装置１２０、システムメモリ１３０、およびシステムメモリを含む様々なシステム構成要素を処理装置１２０に結合するシステムバス１２１が含まれる。システムバス１２１は、メモリバスまたはメモリコントローラ、周辺機器バス、および様々なバスアーキテクチャのいずれかを使用するローカルバスを含むいくつかのタイプのバス構造のいずれかとすることができる。限定ではなく例を挙げると、そのようなアーキテクチャには、ＩＳＡ（Ｉｎｄｕｓｔｒｙ  Ｓｔａｎｄａｒｄ  Ａｒｃｈｉｔｅｃｔｕｒｅ）バス、ＭＣＡ（Ｍｉｃｒｏ  Ｃｈａｎｎｅｌ  Ａｒｃｈｉｔｅｃｔｕｒｅ）バス、ＥＩＳＡ（Ｅｎｈａｎｃｅｄ  ＩＳＡ）バス、ＶＥＳＡ（Ｖｉｄｅｏ  Ｅｌｅｃｔｒｏｎｉｃｓ  Ｓｔａｎｄａｒｄｓ  Ａｓｓｏｃｉａｔｉｏｎ）ローカルバス、およびＰＣＩ（Ｐｅｒｉｐｈｅｒａｌ  Ｃｏｍｐｏｎｅｎｔ  Ｉｎｔｅｒｃｏｎｎｅｃｔ）バス（メザニンバスとしても知られる）が含まれる。
【００１６】
コンピュータ１１０は、一般に、様々なコンピュータ可読媒体を含む。コンピュータ可読媒体は、コンピュータ１１０によってアクセスすることができる任意の入手可能な媒体とすることができ、揮発性媒体と不揮発性媒体、取外し式と非取外し式の媒体を共に含む。限定ではなく例を挙げると、コンピュータ可読媒体は、コンピュータ記憶媒体と通信媒体を含む。コンピュータ記憶媒体には、コンピュータ可読命令、データ構造、プログラムモジュール、または他のデータなど、情報を記憶するための任意の方法または技術で実施される揮発性と不揮発性、取外し式と非取外し式の媒体が共に含まれる。コンピュータ記憶媒体には、それだけには限らないが、ＲＡＭ、ＲＯＭ、ＥＥＰＲＯＭ、フラッシュメモリもしくは他のメモリ技術、ＣＤ−ＲＯＭ、デジタル多用途ディスク（ＤＶＤ）もしくは他の光ディスク記憶装置、磁気カセット、磁気テープ、磁気ディスク記憶装置もしくは他の磁気記憶デバイス、または、所望の情報を記憶するために使用することができ、コンピュータ１１０によってアクセスすることができる他の任意の媒体が含まれる。通信媒体は、一般に、コンピュータ可読命令、データ構造、プログラムモジュール、または他のデータを、搬送波または他の移送機構など変調データ信号に統合し、任意の情報送達媒体を含む。「変調データ信号」という用語は、情報を信号に符号化するようにその特性の１つまたは複数が設定された、または変化した信号を意味する。限定ではなく例を挙げると、通信媒体は、有線ネットワークまたは直接配線接続など有線媒体と、音響、ＲＦ、赤外線および他の無線媒体など無線媒体とを含む。上記のいずれかの組合せもまた、コンピュータ可読媒体の範囲内に含まれるべきである。
【００１７】
システムメモリ１３０は、ＲＯＭ１３１およびＲＡＭ１３２など揮発性および／または不揮発性メモリの形態でコンピュータ記憶媒体を含む。起動中などにコンピュータ１１０内の要素間で情報を転送するのを助ける基本ルーチンを含む基本入出力システム（ＢＩＯＳ１３３）は、一般にＲＯＭ１３１内に記憶されている。一般にＲＡＭ１３２は、処理装置１２０によって直ちにアクセス可能な、および／または現在動作されているデータおよび／またはプログラムモジュールを含む。限定ではなく例を挙げると、図１は、オペレーティングシステム１３４、アプリケーションプログラム１３５、他のプログラムモジュール１３６、プログラムデータ１３７を示す。
【００１８】
コンピュータ１１０はまた、他の取外し式／非取外し式、揮発性／不揮発性コンピュータ記憶媒体を含むことができる。たとえば、図１は、非取外し式の不揮発性磁気媒体との間で読出しまたは書込みをするハードディスクドライブ１４１、取外し式の不揮発性磁気ディスク１５２との間で読出しまたは書込みをする磁気ディスクドライブ１５１、ＣＤ−ＲＯＭまたは他の光媒体など取外し式の不揮発性光ディスク１５６との間で読出しまたは書込みをする光ディスクドライブ１５５を示す。例示的な動作環境内で使用することができる他の取外し式／非取外し式、揮発性／不揮発性コンピュータ記憶媒体には、それだけには限らないが、磁気テープカセット、フラッシュメモリカード、デジタル多用途ディスク、デジタルビデオテープ、固体ＲＡＭ、固体ＲＯＭなどが含まれる。一般にハードディスクドライブ１４１は、インターフェース１４０など非取外し式メモリインターフェースを介してシステムバス１２１に接続され、磁気ディスクドライブ１５１および光ディスクドライブ１５５は、一般に、インターフェース１５０など取外し式メモリインターフェースによってシステムバスに接続されている。
【００１９】
上記で論じ、図１に示されたドライブとその関連コンピュータ記憶媒体は、コンピュータ１１０のためのコンピュータ可読命令、データ構造、プログラムモジュール、および他のデータを記憶する。たとえば、図１では、ハードディスクドライブ１４１が、オペレーティングシステム１４４、アプリケーションプログラム１４５、他のプログラムモジュール１４６、プログラムデータ１４７を記憶して示されている。これらの構成要素は、オペレーティングシステム１３４、アプリケーションプログラム１３５、他のプログラムモジュール１３６、プログラムデータ１３７と同じとすることも異なっていることもできる。ここでは、オペレーティングシステム１４４、アプリケーションプログラム１４５、他のプログラムモジュール１４６、プログラムデータ１４７は、これらが最低でも異なるコピーであることを示すために異なる番号が与えられている。ユーザは、キーボード１６２、および一般にマウス、トラックボール、またはタッチパッドと呼ばれるポインティングデバイス１６１など、入力デバイスを介してコンピュータ１１０にコマンドおよび情報を入力することができる。他の入力デバイス（図示せず）には、マイクロフォン、ジョイスティック、ゲームパッド、衛星パラボラアンテナ（パラボラアンテナは、コンピュータに入力すべき信号を受信するために使用される）、スキャナなどが含まれる。これらの、また他の入力デバイスは、システムバスに結合されているユーザ入力インターフェース１６０を介して処理装置１２０に接続されることがしばしばであるが、パラレルポート、ゲームポート、またはユニバーサルシリアルバス（ＵＳＢ）など、他のインターフェースおよびバス構造によって接続することができる。モニタ１９１または他のタイプのディスプレイデバイスもまた、ビデオインターフェース１９０などのインターフェースを介してシステムバス１２１に接続することができる。モニタに加えて、コンピュータはまた、スピーカ１９７やプリンタ１９６など他の周辺出力デバイスをも含むことができ、これらは、出力周辺機器インターフェース１９５を介して接続することができる。
【００２０】
コンピュータ１１０は、リモートコンピュータ１８０など、１つまたは複数のリモートコンピュータに対する論理接続を使用してネットワーク環境内で動作することができる。リモートコンピュータ１８０は、パーソナルコンピュータ、サーバ、ルータ、ネットワークＰＣ、ピアデバイスまたは他の共通ネットワークノードとすることができ、図１には、メモリ記憶デバイス１８１だけが示されているが、一般に、コンピュータ１１０に関して上述した要素の多数または全部を含む。図の論理接続は、ローカルエリアネットワーク（ＬＡＮ）１７１と広域ネットワーク（ＷＡＮ）１７３を含むが、他のネットワークを含むこともできる。そのようなネットワーク環境は、事務所、全社コンピュータネットワーク、ストレージエリアネットワーク（ＳＡＮ）、イントラネット、インターネットで普通である。
【００２１】
コンピュータ１１０は、ＬＡＮネットワーク環境内で使用されるとき、ネットワークインターフェースまたはアダプタ１７０を介してＬＡＮ１７１に接続される。コンピュータ１１０は一般に、ＷＡＮネットワーク環境内で使用されるとき、インターネットなどＷＡＮ１７３を介して通信を確立するためのモデム１７２または他の手段を含む。モデム１７２は、内部にあっても外部にあってもよく、ユーザ入力インターフェース１６０または他の適切な機構を介してシステムバス１２１に接続することができる。ネットワーク環境では、コンピュータ１１０に関して図示されたプログラムモジュール、またはその一部分を、遠隔メモリ記憶装置内に記憶することができる。限定ではなく例を挙げると、図１は、メモリデバイス１８１に常駐するリモートアプリケーションプログラム１８５を示す。図のネットワーク接続は例であり、コンピュータ間で通信リンクを確立する他の手段を使用することができることは理解されよう。
【００２２】
Ｂ．概要：バージョン付きノードおよび左リンク
本発明は、一般に、同時実行性Ｂツリーをトラバースするための先の方法に改良を加え、具体的には、Ｙｅｈｏｓｈｕａ  Ｓａｇｉｖによるアルゴリズム（これを「Ｓａｇｉｖアルゴリズム」と称する）に改良を加える。上記で論じたように、Ｂツリーは、「値」（従業員記録など）に対する「キー」（従業員番号など）の関連付けを維持するデータ構造である。一般にＢツリーは、ディスク上に記憶される。Ｂツリーは、大抵の情報検索システムの基礎にある。
【００２３】
図２は、典型的な情報検索システム２００を示す。図では、そのようなシステムは、サーバ２０２と、データベースなど持続性ストア２０４とを含むことができる。さらに、ストア２０４内に常駐するデータは、Ｂ−リンク−ツリー２０６などツリーの形態に編成することができる。そのようなデータ構造は、ノードＮ１、Ｎ２、Ｎ３などを含み、インデックスノードの場合には、各ノードから少なくとも１つの他のノードへのリンクを含む（データノードは、一般に入来リンクを有するだけである）。ノードは、ディスクブロックに対応するようにサイズ決めすることができ、あるいは、より大きくすることも、より小さくすることもでき、データノードおよびインデックスノードとして形成することができる（図３Ａと共に下記でさらに論じる）。さらに、ルートノード（図２のノードＮ１）と子ノードがあり、兄弟ノードは、共通の親を有するノードである（たとえば、ノードＮ２およびＮ３は兄弟である）。インデックスノードはまた、図のように、その右兄弟にリンクすることができる。
【００２４】
一般に情報検索システムは、情報検索システムによって維持されているデータへの同時アクセスとその更新をサポートし、これは、基礎となるＢツリー上で複数の同時ルックアップ動作および更新動作が存在する可能性があることを意味する。これらの同時動作がＢツリーを破損しないようにするために、何らかの同期方式が必要とされる。典型的な同時実行性Ｂツリーアルゴリズムは、ツリーのノードレベルで同時動作を同期する。すなわち、ツリーのノードを修正したいと望む動作は、同じノード上で別の同時更新（または他の）動作と干渉しないことを保証するために、そのノードに対してロックを獲得しなければならない。
【００２５】
ロック獲得は、いくつかの点に関して高価である。すなわち、（特にＢツリーが複数のコンピュータを跨いで複製されるとき、ロックを遠隔ロックサーバから獲得しなければならないことを意味し）コンピュータ的に高価となる可能性があり、同時実行性を制限する。したがって、（アルゴリズムの正しさを損なうことなしに）ロック獲得数を最小限に抑えることが望ましい。多くの調査がこのテーマに対して向けられている（上記で引用した非特許文献５は、この問題に対して優れた調査を含む）。知る限りでは、ロック獲得数を最小限に抑えることに関して最も良好に動作するＢツリーアルゴリズムは、Ｓａｇｉｖアルゴリズムである（上記で引用した非特許文献４参照）。
【００２６】
本明細書で述べられているシステムは、２つの点でＳａｇｉｖのアルゴリズムを改善する。第１に、Ｓａｇｉｖのアルゴリズムの非効率、すなわち、データレコードを突き止めようと試みる間に動作が「迷子」になる可能性があり、再開始しなければならない非効率を回避し、第２に、Ｓａｇｉｖの技法は追加のロックを必要とするが、追加のロック獲得を必要としない、削除済みノードをガーベッジコレクションするための方式を導入する。この２つの最適化は互いに独立であり、すなわち、一方または両方を追加することによってＳａｇｉｖのアルゴリズムを改善することができる。
【００２７】
本発明について述べる前に、一般にＢツリーを、また具体的にはＳａｇｉｖのアルゴリズムを概観するのが有用である。
【００２８】
Ｃ．ＢツリーおよびＳａｇｉｖアルゴリズム
Ｂツリーは、値とのキーの関連付けを維持するデータ構造である。キー全体にわたって全体の順序が存在すること、すなわち、一方のキーが他方より大きいかどうか判断することが常に可能であることが前提条件である。図２、参照番号２０８で示されているように、Ｂツリーは、以下の３つの基本動作をサポートする。
１）キーｋを値ｖに関連付けるｉｎｓｅｒｔ（ｋ，ｖ）
２）キーｋに関連付けられた値ｖを返すｌｏｏｋｕｐ（ｋ）
３）キーｋをその関連付けられた値から分離するｄｅｌｅｔｅ（ｋ）
【００２９】
Ｂツリーは、最初にＢａｙｅｒおよびＭｃＣｒｅｉｇｈｔによって述べられた（上記で引用した非特許文献１）。Ｂ＊ツリー（上記で引用した非特許文献６参照）、Ｂ＋ツリー（上記で引用した非特許文献２参照）、およびＢ−リンクツリー（上記で引用した非特許文献３参照）を含む、Ｂツリーの多数の変形形態がある。Ｓａｇｉｖのアルゴリズムは、Ｂ−リンクツリーを使用する。本発明は、すべてのタイプのＢツリーとその変形形態に適用可能であり、本発明について述べる際に本明細書で使用されるＢツリーという用語は、基本的なＢツリー構造の変形形態すべてを包含するものとする。本発明の好ましい実施形態は、新しい形態のＢ−リンクツリーを使用する。
【００３０】
Ｂ−リンクツリーは（また実際にはどのＢツリーも）、キーおよび値、ならびにメタデータをノード内に記憶する。ノードは、ディスクまたは何らかの他の記憶装置上で維持され（Ｂツリーは、任意の低速、安価な記憶装置について理にかなう）、要求に応じてメインメモリ内に読み込まれ、修正された場合、ディスクに書き戻される。ディスク上のノードは、ハンドルによって識別される。（本考察では、ハンドルを、記憶ブロックの連続する範囲のアドレス（たとえば、ディスクブロックアドレス）に任意選択のメタデータを加えたものと考えれば十分である。）図２、参照番号２１０に示されているように、アロケータは、ノードをディスク上で維持し、以下の４つの動作をサポートするソフトウェアコンポーネントである。
【００３１】
１）ｎバイトの最大サイズで、あるノードについてディスク上の空間を予約し、ノードにハンドルを返すａｌｌｏｃａｔｅ（ｎ）
２）ハンドルｈによって識別されたディスクロケーションの空間を放棄するｄｅａｌｌｏｃａｔｅ（ｈ）
３）ハンドルｈによって識別されたディスクロケーションからノードを読み取り、それを返すｒｅａｄ（ｈ）
４）メインメモリからハンドルｈによって識別されたディスクロケーションにノードＡを書き込むｗｒｉｔｅ（ｈ，Ａ）
【００３２】
以下の考察では、アロケータ動作が微小である、すなわち、同じハンドルに対する２つの同時動作が互いに干渉しないと仮定する。
Ｂツリー内のノードは、他のノードを参照するハンドルを含むことができる。大抵のＢツリー変形形態では、ノード群を接続して、有向／連結／非輪状グラフであるツリー（したがって名前）を形成する。以下では、ツリー、および部分ツリー、リンク、ルート、リーフ、親、子、兄弟という用語の定義を熟知しているものと仮定する。Ｂ−リンクツリーは、親から子へのリンクに加えて、あらゆるノードがその直接隣接する右兄弟へのリンク（そのような兄弟が存在する場合）を有する点で正規のツリーと異なる。これは図３Ａの例示的なＢ−リンクツリー３００においてわかり、「右リンク」（右兄弟へのリンク）が参照番号３０２によって表されている。
【００３３】
Ｓａｇｉｖによって使用されているＢ−リンクツリーは、それぞれ図３Ａの参照番号３０４および３０６であるデータノードおよびインデックスノードという２つの異なる種類のノードで構成されている。データノードは、単純に＜ｋ，ｄ＞という形態のキー値の対である。インデックスノードは、
<kmin, h0, k0, h1, k1, ..., hn-1, kn-1, hn, kmax, hright>
という形態である。
【００３４】
以下では、ノードＡのフィールドｘをＡｘと称する。インデックスノードＡ，Ａ．ｈ０．．．とすると、Ａ．ｈｎは、Ａのｎ＋１の子へのハンドルであり、Ａ．ｈｒｉｇｈｔは、その右兄弟へのハンドルである。Ａ．ｋｉ（０＝ｉ＜ｎの場合）は、ハンドルＡ．ｈｉ部をルートとする部分ツリー内の最大キーであり、Ａ．ｋｉ−１（または、ｉ＝０の場合Ａ．ｋｍｉｎ）は、ハンドルＡ．ｈｉ部をルートとする部分ツリー内の最小キーより小さい。Ａ．ｋｍａｘは、Ａのどの部分ツリー内でも最大キー以上であり（Ａが右兄弟を有していない場合には、定義８に従う）、Ａ．ｋｍｉｎは、ＢがＡの左兄弟である場合、Ｂ．ｋｍａｘに等しい（または、Ａが右兄弟を有していない場合には、−８）。さらに、Ａ．ｋｍｉｎ＜Ａ．ｋ０．．．＜Ａ．ｋｎ＝Ａ．ｋｍａｘである。最後に、ｎのサイズに制限がある（ｎは、インデックスノード内のキーとハンドルの数を示す）。ｎが最大値（たとえば、２ｔ）に達した場合には、インデックスノードが満杯であるという。同様に、ｎがある数（たとえば、ｔ）に満たない場合、ノードが満杯未満であるという。
【００３５】
インデックスノード内のキーと、そのノード部をルートとする部分ツリー内のキーとに対する制約のため、Ｂ−リンクツリーは探索ツリー、すなわち、ツリーの中に下降することによって特定のキーを見つけることができるツリーである。直感的には、ｌｏｏｋｕｐ（ｋ）は、ルートハンドルで始まり、対応するノードＡ内で読み取り、Ａ．ｋｉ−１（または、ｉ＝０の場合Ａ．ｋｍｉｎ）＜ｋ＝Ａ．ｋｉ（または、ｉ＝ｎの場合Ａ．ｋｍａｘ）のような値ｉを識別する。次いで、データノードＢに達するまでハンドルＡ．ｈｉに沿って帰納的に進み、Ｂのキーが実際にｋであった場合Ｂの値を返し、そうでない場合にはヌルを返す。
【００３６】
削除動作はルックアップ動作に似ている。すなわち、ｄｅｌｅｔｅ（ｋ）は、キーｋを有するデータノードＤが発見されるまで（そのようなノードが存在する場合）ツリーの中に下降する。次いで、この動作はＤを削除済みとマークし（他の進行中の動作がＤへのハンドルを有しているが、依然としてＤを読み取っていない可能性があるため、Ｄは直ちに割振り解除されない）、Ｄの親ノードＡからＤへのハンドルを除去する。これは、Ａを満杯未満にする可能性がある。
【００３７】
挿入動作はより複雑である。すなわち、ｉｎｓｅｒｔ（ｋ，ｖ）は、新しいデータノードＤにハンドルｈを割り振り、そこに対（ｋ，ｖ）を書き込み、次いで、ｈを受け取るべきリーフインデックスノードＡ（子がデータノードであるインデックスノード）を見つけるまでルックアップと同じ方法でツリーの中に帰納的に下降する。Ａが満杯でない場合には、ｉｎｓｅｒｔ（ｋ，ｖ）は、単にｈおよびｋを適切な場所でＡ内に挿入し、そうでない場合には、新しいインデックスノードＡを割り振り、Ａのキー−ハンドル対の半分をＡの上に移動し、ｋおよびｈをＡ内に挿入し、最後に、ハンドルをＡに、またＡの新しいｋｍａｘをＡの親に追加する（これによりＡの親が満杯超過になり、ノード分割プロセスがツリーを詰めさせる可能性がある）。
【００３８】
上述のように、削除動作は、ノードを満杯未満にする可能性がある。（ツリーを必要とされるより深くすることになり、各動作によって必要とされるディスクアクセス数を増大させることになる）非常に多数のノードが満杯未満になるのを防止するために、バックグラウンドで圧縮スレッドが実行される。このスレッドは、ツリーを繰り返しトラバースし、満杯未満のノードを探索する。満杯未満のノードを突き止めたとき、その左兄弟または右兄弟と再平衡を取るか（これは、キー−ハンドル対をその兄弟からＡに移動すること、およびキーを親ノード内で調整することを必要とする）、あるいは、Ａをその左兄弟または右兄弟と完全にマージする（これは、Ａの内容すべてをその兄弟に移動すること、Ａを削除済みとマークすること、Ａのハンドルとその対応するキーをＡの親から除去することを必要とし、これにより親が満杯未満にされる可能性がある）。
【００３９】
Ｓａｇｉｖのアルゴリズムでは、削除とマークされたノードは、これらのノードにハンドルを有する動作がないことが確実であるときだけ、割振り解除される。これは、各削除済みノードにタイムスタンプを追加し、削除された時間を示し、処理中のあらゆるルックアップ、挿入、削除動作の開始時間を記録するテーブルを維持することによって達成される。このシステムは、削除済みノードのリストを維持する。圧縮スレッドは、リストを周期的に調べ、タイムスタンプが進行中の動作すべての開始時間以前であるまさにそのノードを削除する。この方式の欠点は、開始時間のテーブルが多数のスレッドによってアクセスされ、これは、テーブルをロックによって保護しなければならないことを意味することである。各動作は、（１つはスレッド−開始時間対をテーブルに追加するため、１つはそれを除去するために）２つのロック獲得および解放を必要とする。
【００４０】
同時ルックアップ／挿入／削除動作は、互いに干渉する可能性があることにより、状況はさらに複雑化される。これは、ある動作中にアクセスを受けるあらゆるノードをロックすること、および任意の抽出されたハンドルによって参照される子または兄弟が読み取られた後だけそれをロック解除することによって回避することができるであろう（これは、文献内で「ロックカップリング」と呼ばれる）。Ｓａｇｉｖのアルゴリズムは、動作は通常干渉しないという楽観的な仮定を使用し、この仮定が保証されない場合を検出し、誤りから回復することにより、そのような過剰なロックを回避する。
【００４１】
具体的にするため、動作ｌｏｏｋｕｐ（ｋ）が、ハンドルｈに従うと判断したが、対応するノードＡを読み取ることができるようになる前に、別のスレッドがキー−ハンドル対をＡ内に挿入し、そのプロセスにおいて、Ａを２つのノードＡとＡ（Ａの新しく割り振られた右兄弟）に分割する場合を考えてみる。ルックアップ動作は、Ａを読み取った後で、（ｋ＞Ａ．ｋｍａｘであるため）Ａが分割されたことを検出することができ、（実際に適切な範囲のキーを含む）Ａに導くＡ．ｈｒｉｇｈｔハンドルに従うことによりこの状況から回復することができる。しかし、この高価でない回復は、常に可能であるわけではない。動作ｌｏｏｋｕｐ（ｋ）が、ハンドルｈに従うと判断したが、対応するノードＡを読み取ることができるようになる前に、圧縮スレッドがノードＡを再平衡し（Ａは満杯未満になる）、ルックアップが従うべきハンドルを含むＡの内容の一部をＡの左兄弟Ａに移動する場合を考えてみる。ルックアップ動作は、Ａを読み取った後で、（ｋ＝Ａ．ｋｍｉｎであるため）Ａが再平衡されたことを検出することができるが、ルックアップはＡのハンドルを知らないので、回復するための唯一の方法は、ツリーのルート部でルックアップ動作を再開始することである。
【００４２】
Ｄ．左兄弟へのハンドルを維持すること
本発明の第１の態様によれば、発明者等は、再開始を回避するために、インデックスノードの構造を次のように修正することを提案する。
<hleft, kmin, h0, k0, h1, k1, ..., hn-1, kn-1, hn, kmax, hright>
ただし、ｈｌｅｆｔは、左兄弟のハンドルであり（左兄弟がある場合であり、そうでない場合はヌルである）、他のフィールドすべては、Ｓａｇｉｖのアルゴリズムと同様に定義される。このデータ構造は図３Ｂに示されており、参照番号３００は、修正済みＢ−Ｌｉｎｋデータ構造を指し、参照番号３１０は、特に左リンク、すなわちｈｌｅｆｔを指す。Ｓａｇｉｖのアルゴリズムと同様に、ルックアップ動作、挿入動作、削除動作は、インデックスノードＡのキー範囲が、その動作が突き止めようとしているキーｋを含まないかどうか検出する。Ｓａｇｉｖのアルゴリズムと同様に、動作は、右兄弟へのハンドルＡ．ｈｒｉｇｈｔに従うことによってｋ＞Ａ．ｋｍａｘに反応する。しかし、Ｓａｇｉｖのアルゴリズムは、ルート部で動作を再開始することによってｋ＝Ａ．ｋｍｉｎに反応したが、発明者等のアルゴリズムは、左兄弟へのハンドルＡ．ｈｌｅｆｔに従うことによって反応する。左兄弟へのハンドルに従うことは、１回の追加読取り動作を必要とするが、ルート部で動作を再開始することは、最大（また典型的には約）ｄ回の読取り動作を必要とすることになり、ｄはツリーの深さである。
【００４３】
図３Ｃおよび３Ｄは、それぞれ従来技術によるＳａｇｉｖ式Ｂ−リンクツリー、および本発明による左リンクを含むＢ−リンクツリーのより詳細な例を提供する。これらは、本発明の左リンク態様をさらに例示し、従来技術から区別するように意図されている。
【００４４】
図３Ｃは、マッピング｛（２，ミラー），（５，スミス），（７，ジョーンズ），（１０，ブラウン），（１２，レビン），（１５，ダール），（１７，ルイス），（２０，ユ）｝を含むＳａｇｉｖ式Ｂ−リンクツリーを示す。数はキー値であり、名前は関連データ値である。Ｐはツリーのプライムノードであり、Ｉ１、．．．、Ｉ７はインデックスノードであり、Ｄ１、．．．、Ｄ８はデータノードである。プライムノードは、ハンドルのアレイを含むノードであり、各ハンドルは、ツリーのあるレベルの最も左のインデックスノードを指し、プライムノード内の第１のハンドルは、最も左のリーフインデックスノードを指し、最後のハンドルは、ルートインデックスノードを指す。Ｉ１は、ツリーのルートノードである（すなわち、親を有していない１つのインデックスノード）。プライムノード内の最後のハンドル（この場合はＰ［２］）に従うことによってルートノードに到達する。Ｉ１、Ｉ２、Ｉ３は、非リーフインデックスノードである（すなわち、インデックスノードの子を有するインデックスノード）。これは、Ｉ１．ｈ０が非ヌルであり、ＩｓＬｅａｆ（Ｉ１）（ＩｓＬｅａｆについては以下で述べる。セクションＦ参照）が偽であることを意味する（同じことがＩ２、Ｉ３にも当てはまる）。Ｉ４、Ｉ５、Ｉ６、Ｉ７は、リーフインデックスノード、すなわちインデックスノードの子を有していないインデックスノードである。これは、Ｉ４．ｈ０がヌルであり、ＩｓＬｅａｆ（Ｉ４）が真であることを意味する（同じことがＩ５、Ｉ６、Ｉ７にも当てはまる）。このツリーでは、ｔ＝２である。すなわち、各インデックスノードは、ｋｍｉｎおよびｋｍａｘに加えて２つのキーを保持することができる。Ｉ１、Ｉ２、Ｉ３は、満杯でない（いくつかのフィールドは未使用であり、陰影付けされている）。Ｎｕｍ（Ｉ１）（Ｎｕｍについては以下で述べる。セクションＦ参照）は１である（同じことがＩ２、Ｉ３にも当てはまる）。Ｉ１、Ｉ２、Ｉ３は、それぞれさらに１つのキー−ハンドル対を取ることができる。Ｉ４、Ｉ５、Ｉ６、Ｉ７は満杯である。すなわち、未使用のフィールドがない。Ｎｕｍ（Ｉ４）は２である（Ｉ５、Ｉ６、Ｉ７についても同じ）。
【００４５】
図３Ｄは、図のように左リンクｈｌｅｆｔを含むツリーを示す。このツリーは、図３Ｃのツリーと同じマッピング｛（２，ミラー），（５，スミス），（７，ジョーンズ），（１０，ブラウン），（１２，レビン），（１５，ダール），（１７，ルイス），（２０，ユ）｝を含む。先と同様に、数はキー値であり、名前は関連データ値である。Ｐはツリーのプライムノードであり、Ｉ１、．．．、Ｉ７はインデックスノードであり、Ｄ１、．．．、Ｄ８はデータノードである。Ｉ１は、ツリーのルートノードである（すなわち、親を有していない１つのインデックスノード）。プライムノード内の最後のハンドル（この場合はＰ［２］）に従うことによってルートノードに到達する。Ｉ１、Ｉ２、Ｉ３は、非リーフインデックスノードである（すなわち、インデックスノードの子を有するインデックスノード）。これは、Ｉ１．ｈ０が非ヌルであり、ＩｓＬｅａｆ（Ｉ１）が偽であることを意味する（Ｉ２、Ｉ３についても同じ）。Ｉ４、Ｉ５、Ｉ６、Ｉ７は、リーフインデックスノードである（すなわち、インデックスノードの子を有していないインデックスノード）。これは、Ｉ４．ｈ０がヌルであり、ＩｓＬｅａｆ（Ｉ４）が真であることを意味する（Ｉ５、Ｉ６、Ｉ７についても同じ）。このツリーでは、ｔ＝２である（すなわち、各インデックスノードは、ｋｍｉｎおよびｋｍａｘに加えて２つのキーを保持することができる）。Ｉ１、Ｉ２、Ｉ３は、満杯でない（いくつかのフィールドは未使用であり、陰影付けされている）。Ｎｕｍ（Ｉ１）は１である（Ｉ２、Ｉ３についても同じ）。Ｉ１、Ｉ２、Ｉ３は、それぞれさらに１つのキー−ハンドル対を取ることができる。Ｉ４、Ｉ５、Ｉ６、Ｉ７は満杯である（すなわち、未使用のフィールドがない）。Ｎｕｍ（Ｉ４）は２である（Ｉ５、Ｉ６、Ｉ７についても同じ）。
【００４６】
この着想をさらに例示するために、発明者等は、以下、ルックアップが道に迷った場合にルックアップ動作を再開始するためのコードを含む、Ｓａｇｉｖのルックアップ動作（上記で引用した非特許文献４から採用）の例示的な擬似コードを作成した（ただし、動作開始時間を追跡するための機構は省略する）。
procedure Lookup(hp: ハンドル, k: キー)
var h: ハンドル, A: ノード;
label start:
P:= Read(hp)
h:= Ｐ内の最後のアイテム
repeat
A:= read(h)
if k > A. kmax then 
h:= A.hright
else if k = A.kmin then
goto start
else
A.ki-1 < k= A.kiであるようなｉを選択する（Num(A) = 0の場合iを０にする）。
h:=A.hi
endif
until Ａがリーフである and A.kmin < k = A.kmax
if ｋがＡ内に含まれる then
対応する値を返す。
else
ヌルを返す。
endif
endproc
【００４７】
対照的に、以下は本発明によるルックアップルーチンの一実施に対応する例示的な擬似コードである。（図７は、別の例示的なＬｏｏｋｕｐプロシージャの流れ図を示すことに留意されたい。）わかるように、このルーチンは、動作を再開始する代わりに、左リンクに従う。このプロシージャは、図３Ｅで再現され、ボックス３２０は、左リンクデータを使用するように設計されたコードの新しい行を囲んでいる。コードのこの新しい行は、キー値ｋが、ノードＡのｋｍｉｎフィールド内に記憶された値以下であるかどうか判定し、そうである場合には、左リンクハンドルをハンドル変数に割り当てる（すなわち、ｈ：＝Ａ．ｈｌｅｆｔ）。
procedure Lookup(hp: ハンドル, k: キー)
var h: ハンドル, A: ノード;
P:= Read(hp)
h:= Ｐ内の最後のアイテム
repeat
A:= read(h)
if k > A.kmax then
h:= A.hright
else if k = A.kmin then
h:= A.hleft
else
A.ki-1 < k = A.ki であるようなｉを選択する（Num (A) = 0の場合ｉを０にする）。
h:= A.hi
endif
until Ａがリーフである and A.kmin < k = A.kmax
if ｋがＡ内に含まれる then
対応する値を返す。
else
ヌルを返す。
endif
endproc
【００４８】
Ｅ．バージョン番号をハンドルおよびディスクブロックに添着する
次いで、動作開始時間のテーブルを維持することを回避するための本発明の方法について述べる。具体的には、現在好ましい実施形態では、ハンドルおよびノードにバージョン番号、またはアロケータ２１０（図２）によって返された「割振り単位」を添着することによってこれを行う。上述のように、削除動作によって、または圧縮スレッドによってノードが削除されたとき、同時動作がそれに対するハンドルを有している可能性がある。Ｓａｇｉｖのアルゴリズムは、あらゆる削除済みノードに削除時間を示すタイムスタンプを添着することによって、また、あらゆる動作の開始時間を記録することによってこの問題に対処する。削除済みノードは、ノードが削除済みとマークされたときより前に開始された進行中の動作がないときだけ、「ガーベッジコレクション」される。この解決策は、スレッドを開始時間にマッピングするテーブルをシステムが維持することを必要とし、１つはスレッド−開始時間対をテーブルに追加するため、１つはそれを除去するために２つの同期を必要とする。というのは、テーブルがクライアントスレッドによって変化させられ、圧縮スレッドによってアクセスされるからである。
【００４９】
本発明の現在の好ましい実施によれば、各ハンドルに、また各ノードにバージョン番号が添着される。最初に、各ノードは、バージョン番号０を有する。割振り動作（上述）は、ノードを識別するハンドルを返し、ノードのバージョン番号をハンドル内に埋め込む。割振り解除動作は、（ノードのバージョン番号を後続の再割振りに使用可能にするのに加えて）ノードのバージョン番号を増分する。読取り動作は、ノードに加えて、ノードのバージョン番号を返す。読取り動作（すなわち、ルックアップ、挿入、または削除動作）のコーラーは、読取り動作によって返されたバージョン番号が、読み取られたハンドルのバージョン番号と合致するかどうか検査する。バージョン番号が合致しない場合には、ノードが削除されており、その後で、異なるスレッドによって割振り解除されている。この場合には、ルックアップ、挿入、または削除動作が再開始される。
【００５０】
このバージョン採番方式を使用して、ノードが削除済みとマークされつつあるときに、ノードを割振り解除することが可能である。他の最適化として、ある固定された時間間隔の間、削除済みノードを割振り解除するのを延期することができ、これにより、大抵の実行の長い動作を除くすべてについて、再開始する必要がなくなる。
【００５１】
本発明のこの態様の一代替実施形態では、読取り動作は、読み取られつつあったディスクブロックのバージョン番号を返さず、その代わりに、ハンドルのバージョン番号とディスクブロックのバージョン番号が合致しないときはいつでも、例外を挙げる。読取り動作（すなわち、ルックアップ、挿入、または削除動作）のコーラーは、その例外を捕らえ、ルックアップ、挿入、または削除動作を再開始する。
【００５２】
この着想をさらに例示するために、以下はＳａｇｉｖのルックアップ動作（この場合も、上記で引用した非特許文献４から採用）の例示的な擬似コードであり、今度は、動作開始時間を追跡するための機構をも含む。Ｔは、スレッド識別子を動作開始時間にマッピングするテーブルを参照するグローバル変数である。
procedure Lookup(hp: ハンドル, k: キー)
var h: ハンドル, A: ノード;
label start:
P:= Read(hp)
h:= Ｐ内の最後のアイテム
repeat
lock T
insert (このスレッドのＩＤ, 現在時間) into T
unlock T
A:= read(h)
if k > A.kmax then
h:= A.hright
else if k= A.kmin then
goto start
else
A.ki-1 < k = A.kiであるようなｉを選択する（Num(A) = 0の場合ｉを０にする）。
h:= A.hi
endif
until Ａがリーフである and A.kmin < k= A.kmax
lock T
remove (このスレッドのＩＤ, 対応する時間) from T 
unlock T
if ｋがＡ内に含まれる then
対応する値を返す。
else
ヌルを返す。
endif 
endproc
【００５３】
対照的に、以下は本発明によるルックアップルーチンのための擬似コードの一例であり、このルーチンは、テーブルＴに対するどんな動作も回避する（本発明は２つの独立した部分からなることを強調するために、このバージョンは、再開始を回避するために左リンクを使用することを組み込まない）。
procedure Lookup(hp: ハンドル, k: キー)
var h: ハンドル, A: ノード;
label start:
P:= Read(hp)
h:= Ｐ内の最後のアイテム
repeat
A:= read(h)
if version(A) ≠ version(h) then goto start
if k > A.kmax then
h:= A.hright
else if k = A.kmin then
goto start
else
A.ki-1 < k = A.kiであるようなｉを選択する（Num(A) = 0の場合ｉを０にする）。
h:= A.hi
endif
until Ａがリーフである and A.kmin < k = A.kmax
if ｋがＡ内に含まれる then
対応する値を返す。
else
ヌルを返す。
endif 
endproc
【００５４】
この擬似コードは図３Ｆにも示され、ボックス３３０は、コードの新しい行（Ｉｆ  ｖｅｒｓｉｏｎ（Ａ）≠ｖｅｒｓｉｏｎ（ｈ）  ｔｈｅｎ  ｇｏｔｏ  ｓｔａｒｔ）を示すことに留意されたい。さらに、この新しい擬似コードは、ロック動作に関してＳａｇｉｖアルゴリズムからのコードの行を含まない。換言すれば、以下のコードが省略されている。
【００５５】
ｌｏｃｋ  Ｔ
ｉｎｓｅｒｔ（このスレッドのＩＤ，現在時間）ｉｎｔｏ  Ｔ
ｕｎｌｏｃｋ  Ｔ
さらに、コード
ｌｏｃｋ  Ｔ
ｒｅｍｏｖｅ（このスレッドのＩＤ，対応する時間）ｆｒｏｍ  Ｔ
ｕｎｌｏｃｋ  Ｔ
が除去されている。
【００５６】
当然ながら、本明細書で開示されている２つの改良を組み合わせて、双方の利益を得ることができる。挿入動作および削除動作、ならびに圧縮スレッドの擬似コードは、より著しく複雑であるが、それでもなお十分に当業者の能力の範囲内である。さらに、本発明を組み込むために必要とされる修正は、本明細書を読んだ後で容易になるはずである。
【００５７】
Ｆ．例示的なプロシージャの流れ図
図４〜１０は、本発明によるアルゴリズムの現在好ましい実施と共に使用することができるいくつかのプロシージャを表す流れ図である。以下の表は、これらの流れ図内で言及されるデータタイプ、表記法、関数（インデックスノードおよびアロケータ関数群）を要約する。
【００５８】
【表１】
2004185617.tif 000003
【００５９】
図４は、ＧｅｔＮｅｘｔＨａｎｄｌｅという名称のプロシージャの流れ図である。このプロシージャは、インデックスノードＸとキーｋを取り、（ｈ，ｉｓＬｉｎｋ）を返し、ただしｈは、ツリーの中で、キーｋとその関連データ値を含むデータノードにより近いＸの子または兄弟を参照するハンドルであり、ｉｓＬｉｎｋは、ｈがＸの兄弟へのリンクであるかどうかを示すブール値である。図４に示すように、このプロシージャは、ＧｅｔＮｅｘｔＨａｎｄｌｅ（Ｘ，ｋ）のためのエントリポイント４０２で始まる。ステップ４０４で、このプロシージャは、ｋがＸ．ｋｍｉｎ以下であるかどうか判定し、ただしＸ．ｋｍｉｎは、インデックスノードＸのフィールドｋｍｉｎを指す。Ｘ．ｋｍｉｎ以下である場合には、このプロシージャは（Ｘ．ｈｌｅｆｔ，ｔｒｕｅ）を返し、Ｘの左兄弟が所望のデータノードにより近いことを示す。Ｘ．ｋｍｉｎ以下でない場合には、このプロシージャは、ｋがＸ．ｋｍａｘより大きいかどうか判定し、大きい場合には（Ｘ．ｈｒｉｇｈｔ，ｔｒｕｅ）を返し、Ｘの右兄弟が所望のデータノードにより近いことを示す（ステップ４１０）。ステップ４０８で決定され、ｋがＸ．ｋｍａｘより大きくない場合には、このプロシージャは、Ｎｕｍ（Ｘ）が０に等しいかどうか判定し（ステップ４１２）、等しい場合には、ステップ４１４で（Ｘ．ｈ０，ｆａｌｓｅ）を返す。ステップ４１６に移動して、このプロシージャは、Ｘ．ｋｎ−１がｋ未満であるかどうか判定する。ｋ未満である場合には、このプロシージャは、ステップ４１８で（Ｘ．ｈｎ，ｆａｌｓｅ）を返す。ｋ未満でない場合には、このプロシージャはステップ４２０に移動し、ｋがＸ．ｋｉ以下であるような最小のｉを見つける。次いで、ステップ４２２で、このプロシージャは、ＩｓＬｅａｆ（Ｘ）が真であるかどうかテストする。真である場合には、（Ｘ．ｈｉ＋１，ｆａｌｓｅ）を返し（ステップ４２４）、真でない場合には、（Ｘ．ｈｉ，ｆａｌｓｅ）を返す（ステップ４２６）。要するに、図４のプロシージャは、ハンドルと、そのハンドルがノードＸの兄弟へのリンクであるかどうかを示すブールフラグとを返す。
【００６０】
図５は、インデックスノードＸ、キーｋ、ハンドルｈを取り、キーｋおよびハンドルｈをＸに挿入するＩｎｓｅｒｔＰａｉｒという名称のプロシージャの流れ図である。このプロシージャは、何も返さない。
【００６１】
図５に示すように、このプロシージャは、エントリポイントＩｎｓｅｒｔＰａｉｒ（Ｘ，ｋ，ｈ）で始まる（ステップ５０２）。次いで、ステップ５０４で、このプロシージャは、Ｎｕｍ（Ｘ）が０に等しいかどうか判定する。等しい場合には、ステップ５０６で、図のようにキーｋおよびハンドルｈがノードＸに挿入される。Ｎｕｍ（Ｘ）が０に等しくない場合には、ステップ５０８で、このプロシージャはＸ．ｋ０がｋ未満であるかどうか判定し、ｋ未満でない場合にはステップ５１０に進み、ここで図のようにキーｋおよびハンドルｈがノードＸに挿入される。一方、このプロシージャは、Ｘ．ｋ０がｋ未満であると決定した場合にはステップ５１２に進み、ここでＸ．ｋｉ−１がｋ未満であるような最大のｉを見つけ、次いでステップ５１４で、図のようにキーｋおよびハンドルｈをノードＸに挿入する。最後に、ステップ５１６で、プロシージャが戻る。要するに、キーｋおよびハンドルｈは、Ｎｕｍ（Ｘ）が０に等しいかどうか、およびＸ．ｋ０がｋ未満であるかどうかに応じて、ステップ５０６、５１０、または５１４でノードＸに挿入される。
【００６２】
図６は、ＣｒｅａｔｅＴｒｅｅという名称のプロシージャの流れ図である。このプロシージャは引数を受け取らず、新しいツリーを識別するプライムノードハンドルｈｐを返す。図のように、ＣｒｅａｔｅＴｒｅｅプロシージャ６００は、エントリポイントＣｒｅａｔｅＴｒｅｅ（）で始まる（ステップ６０２）。ステップ６０４で、ノードＸが、（ｎｕｌｌ，−ｉｎｆ，ｎｕｌｌ，＋ｉｎｆ，ｎｕｌｌ）と定義される。ステップ６０６で、ハンドルｈｘが、Ａｌｌｏｃ（Ｘのための空間）と定義され、ただし、関数Ａｌｌｏｃ（）は、引数によって与えられたサイズのブロックを割り振り、そのブロックへのハンドルを返す。次に、ステップ６０８で、このプロシージャは、ハンドルｈｘによって参照されるブロックにノードＸを書き込むためにＷｒｉｔｅ（Ｘ，ｈｘ）を呼び出す。ステップ６１０で、このプロシージャは、ハンドルｈｘを容れるようにプライムノードＰを定義する。ステップ６１２で、このプロシージャは、Ｐを記憶するのに十分な大きさのブロックを割り振るために、再び関数Ａｌｌｏｃ（Ｐのための空間）を呼び出し、Ａｌｌｏｃ（）は、そのブロックへのハンドルｈｐを返す。ステップ６１４で、このプロシージャは、ハンドルｈｐによって参照されるブロックにノードＰを書き込み、ステップ６１６で、このプロシージャは、ハンドルｈｐを返すことによって終わる。要するに、このプロシージャは、新しいツリーを識別するプライムノードハンドルｈｐを返す。
【００６３】
図７は、プライムノードハンドルｈｐおよびキーｋを取り、データアイテムｄまたはヌルを返すＬｏｏｋｕｐという名称のプロシージャの流れ図である。Ｌｏｏｋｕｐプロシージャ７００は、エントリポイントＬｏｏｋｕｐ（ｈｐ，ｋ）で始まる（ステップ７０２）。ステップ７０４で、このプロシージャは、ハンドルｈｐによって指されるブロックを読み取るために、関数Ｒｅａｄ（ｈｐ）を呼び出す。Ｒｅａｄ関数は、（ｖ，Ｐ）すなわちブロックのバージョン番号ｖと、ブロック内に記憶されたプライムノードＰとを返す。次に、ステップ７０６で、ハンドルｈが、プライムノードＰ内の最後のハンドルとして定義され、それによってツリーのルートノードを参照する。ステップ７０８で、このプロシージャは、ハンドルｈによって指されるブロックを読み取るために、再び関数Ｒｅａｄ（）を呼び出す。今度はこの関数は、バージョン番号ｖと、ハンドルｈによって参照されるブロック内に記憶されたインデックスノードＸとを返す。ステップ７１０で、このプロシージャは、ｈ．ｖ（すなわち、ハンドルｈのバージョン番号）がｖに等しいかどうか判定する。等しくない場合には、このプロシージャは、図のようにステップ７０４に戻る。等しい場合には、このプロシージャはステップ７１２に進み、ここで（図４と共に上述した）関数ＧｅｔＮｅｘｔＨａｎｄｌｅが呼び出される。この場合には、関数ＧｅｔＮｅｘｔＨａｎｄｌｅ（Ｘ，ｋ）は、ハンドルｈと、このハンドルｈがノードＸの兄弟へのリンクであるかどうかを示すブールのｉｓＬｉｎｋとを返す。次に、ステップ７１４で、このプロシージャは、ハンドルｈがヌルであるかどうかテストする。ヌルである場合には、このプロシージャはステップ７１６に進み、ここでヌルが返される。ヌルでない場合には、このプロシージャはステップ７１８に進み、ここでＩｓＬｅａｆ（Ｘ）とｎｏｔ  ｉｓＬｉｎｋがどちらも真であるかどうか判定する。共に真でない場合には、このプロシージャは、図のようにステップ７０８に戻る。一方、ＩｓＬｅａｆ（Ｘ）とｎｏｔ  ｉｓＬｉｎｋがどちらも真である場合には、このプロシージャはステップ７２０に進み、ここで、ハンドルｈによって指されるブロックを読み取り、それによってブロックのバージョン番号ｖと、ブロック内に記憶されたデータノードＤとを決定するために、関数Ｒｅａｄ（ｈ）が呼び出される。次に、ステップ７２２で、このプロシージャは、ｈ．ｖ（すなわち、ハンドルｈのバージョン番号）がｖに等しいかどうか判定する。等しくない場合には、このプロシージャは、図のようにステップ７０４に戻り、等しい場合には、ステップ７２４に進む。ステップ７２４で、このプロシージャは、Ｄ．ｋがｋに等しいかどうか（すなわち、データノードＤのキーがｋに等しいかどうか）判定する。等しくない場合には、このプロシージャはステップ７２６に進み、ここでヌルを返し、等しい場合にはステップ７２８に進み、Ｄ．ｄすなわちデータノードＤのデータ部分を返す。したがって、要するに、Ｌｏｏｋｕｐプロシージャは、プライムノードハンドルｈｐおよびキーｋを取り、データアイテムｄまたはヌルを返す。
【００６４】
図８は、プライムノードハンドルｈｐおよびキーｋを取り、ハンドルｈｐによって識別されたツリーからキーとその関連データ値を削除するＤｅｌｅｔｅという名称のプロシージャの流れ図である。このプロシージャは、何も返さない。
【００６５】
図のように、Ｄｅｌｅｔｅプロシージャ８００は、エントリポイントＤｅｌｅｔｅ（ｈｐ，ｋ）で始まる（ステップ８０２）。次に、ステップ８０４で、このプロシージャは、ハンドルｈｐによって指されるブロックを読み取るために、関数Ｒｅａｄ（ｈｐ）を呼び出す。この関数は、ブロックのバージョン番号ｖと、ブロック内に記憶されたプライムノードＰとを返す。次に、ステップ８０６で、ハンドルｈが、ノードＰ内の最後のハンドルとして定義され、それによってツリーのルートノードを参照する。ステップ８０８で、ハンドルｈによって指されるブロックを読み取り、ブロックのバージョン番号と、ブロック内に含まれるインデックスノードＸとを返すために、このプロシージャは再び関数Ｒｅａｄ（）を呼び出す。ステップ８１０で、このプロシージャは、ｈ．ｖがｖに等しいかどうか、すなわち、ハンドルｈのバージョン番号が、先のＲｅａｄ（）の呼出しによって返されたバージョン番号と等しいかどうか判定する。等しくない場合には、このプロシージャは、図のようにステップ８０４に戻り、等しい場合には、ステップ８１２に進む。ステップ８１２で、（図４と共に上記で論じた）関数ＧｅｔＮｅｘｔＨａｎｄｌｅが引数Ｘ，ｋを伴って呼び出される。このようにして、このプロシージャは、ハンドルｈと、このハンドルｈがノードＸの兄弟へのリンクであるかどうかを示すブールのｉｓＬｉｎｋとを決定する。次に、ステップ８１４で、このプロシージャは、ＩｓＬｅａｆ（Ｘ）とｎｏｔ  ｉｓＬｉｎｋがどちらも真であるかどうかテストし、そうでない場合には、このプロシージャはステップ８０８に戻り、そうである場合にはステップ８１６に進む。ステップ８１６で、このプロシージャは、ハンドルｈがヌルであるかどうかテストし、ヌルである場合には、ステップ８１８に進み、ここで戻る。ｈがヌルでない場合には、このプロシージャはステップ８２０に進み、ここで、ハンドルｈによって指されるブロックをロックするために、関数Ｌｏｃｋ（ｈ）が呼び出される。次に、ステップ８２２で、Ｒｅａｄ（ｈ）が、ハンドルｈによって指されるブロックを読み取り、ブロックのバージョン番号と、ブロック内に含まれるインデックスノードＸとを返す。ステップ８２４で、このプロシージャは、ｈ．ｖがｖに等しいかどうかテストし、等しくない場合にはステップ８２６に進み、ここでハンドルｈによって指されるブロックがロック解除され、その後、このプロシージャは、図のようにステップ８０４に戻る。一方、ｈ．ｖがｖに等しい場合には、このプロシージャはステップ８２８（図８の下位区分図８Ｂ参照）に進み、ここでこのプロシージャは、キーｋがＸ．ｋｍｉｎ以下であるかどうか、すなわち、Ｘの左兄弟の１つに添着されたデータノード内でキーｋが見つかるかどうか判定する。Ｘ．ｋｍｉｎ以下である場合には、このプロシージャは、ステップ８３０および８３２に進み、ここで、ハンドルｈによって指されるブロックがロック解除され、次いでハンドルｈが、ノードＸの左兄弟ハンドルとして定義される。ｋがＸ．ｋｍｉｎ以下でない場合には、このプロシージャはステップ８３４に進み、ここでｋがＸ．ｋｍａｘより大きいかどうかテストし、大きい場合には、ステップ８���６および８３８に進み、ここで、ハンドルｈによって指されるブロックをロック解除し、ｈをノードＸの右兄弟ハンドルと定義する。ステップ８３４で、このプロシージャは、ｋがＸ．ｋｍａｘより大きくないと決定した場合、ステップ８４０に進み、ここで、Ｎｕｍ（Ｘ）が０に等しく、Ｘ（リーフレベルのインデックスノード）が子を有していないこと、したがってキーｋを含まないことを意味するかどうかテストする。このテストに対する答が「はい」である場合には、このプロシージャはステップ８５６に進み、「いいえ」である場合には、ステップ８４２に進む。ステップ８４２で、このプロシージャは、Ｘ．ｋｎ−１がｋ未満であるかどうか、すなわち、ノードＸのフィールドｋｎ−１がキー値ｋ未満であるかどうか判定する。ｋ未満である場合には、このプロシージャは、図のようにステップ８５６に跳び、ｋ未満でない場合にはステップ８４４に進み、ここで、ｋがＸ．ｋｉ以下であるような最小のｉを見つける。次に、ステップ８４６で、このプロシージャはＲｅａｄ（Ｘ，ｈｉ＋１）を呼び出し、データノードＤおよびバージョン番号ｖを含むブロックを読み取る。次に、ステップ８４８で、このプロシージャは、Ｄ．ｋがｋに等しいかどうかテストする。等しくない場合には、このプロシージャはステップ８５６に跳び、等しい場合にはステップ８５０に進み、ここで、ブロックバージョン番号を増分するハンドルＸ．ｈｉ＋１によって指されるブロックを割振り解除する。次に、ステップ８５２で、このプロシージャは、Ｘ．ｋｉおよびＸ．ｈｉ＋１によって識別されたハンドルをノードＸから除去する。ステップ８５４で、ハンドルｈによって参照されるノードＸを書き込むためにＷｒｉｔｅ（）が呼び出される。最後に、ステップ８５６および８５８で、ハンドルｈによって指されるブロックがロック解除され、プロシージャが戻る。要するに、Ｄｅｌｅｔｅプロシージャは、プライムノードハンドルｈｐおよびキーｋを取り、ｈｐによって識別されたツリーからキーｋとその関連データ値を除去する。
【００６６】
図９は、プライムノードハンドルｈｐ、キー値ｋ、データ値ｄを取り、ｈｐによって識別されたツリーにキー値とデータ値を挿入するＩｎｓｅｒｔという名称のプロシージャの流れ図である。Ｉｎｓｅｒｔ関数９００は、参照番号９０１によって識別されたエントリポイントで始まり、呼出しＩｎｓｅｒｔ（ｈｐ，ｋ，ｄ）によって呼び出され、ただし、ｈｐはプライムノードハンドル、ｋはキー値、ｄはデータ値である。ステップ９０２で、データノードＤがキー値ｋおよびデータ値ｄによって定義される。ステップ９０３で、Ｄを容れるのに十分な大きさのブロックを割り振るように、Ａｌｌｏｃ関数が呼び出され、そのブロックを識別するハンドルがｈＤに割り当てられる。次に、ステップ９０４で、このプロシージャは、ハンドルｈＤによって参照されるブロックにノードＤを書き込む。ステップ９０５で、ＬＴが０に設定され、次いでステップ９０６で、新しい空スタックとしてＳが定義される。さらなる背景を提供するために、発明者等は、ツリーの複数のレベルが兄弟の集合群であることを指摘する。本明細書で使用される用語では、レベル０はリーフインデックスノードすべてを含み、レベル１はその親を含み、以下同様であり、最も高いレベルはルートノードを含む。最も高いレベルの数は、プライムノード内のハンドルの数より１つ少ない（ゼロをベースとするインデックス付けを使用しているためである）。「標的レベル」変数ＬＴは、キー−ハンドル対（ｋ，ｈＤ）がツリーに挿入されるレベルを識別する。ＬＴを０に設定することは、この対がリーフインデックスノードに挿入されることを意味する。アルゴリズムが展開するにつれて、ＬＴを増分することができ、（修正済み）キー−ハンドル対が、ツリーのより高い方（潜在的には、ルートまでの途中すべて）でインデックスノードに挿入されることを示す。ステップ９０７で、Ｒｅａｄ（）関数が呼び出され、バージョン番号ｖと、ブロック内に記憶されたプライムノードＰとを識別するように、ハンドルｈｐによって指されるブロックを読み取る。ステップ９０８で、ノードＰ内の最後のハンドル（ルートインデックスノード）がｈｘに割り当てられる。ステップ９０９で、ＬＮがノードＰ内のハンドルの数となるように定義され、これはツリーの中のインデックスノードレベルの数と同一である。ステップ９１０で、ＬＣがＬＮ−１と定義される。ＬＣ（「現在レベル」）は、挿入プロシージャが現在あるレベルである。Ｉｎｓｅｒｔはルート（上述のように、レベルＬＮ−１にある）で開始されるため、ＬＣは、この値に初期化され、Ｉｎｓｅｒｔがツリーの中に下降するにつれて減分される。ステップ９１２で、Ｒｅａｄ（ｈｘ）が呼び出され、バージョン番号ｖと、ハンドルｈｘによって指されるインデックスノードＸとを返す。ステップ９１３で、このプロシージャは、ｈｘ．ｖがｖに等しいかどうかテストし、ステップ９１４で、このプロシージャは、ＬＣがＬＴより大きいかどうかテストする。ステップ９１３および９１４のテスト双方に対する答が「はい」である場合には、このプロシージャは、ステップ９１５に進む。一方、ステップ９１３に対する答が「いいえ」の場合には、このプロシージャは、図のようにステップ９０６に戻る。ステップ９１４のテストに対する答が「いいえ」の場合には、このプロシージャは、ステップ９２０に進む（図９の下位区分図９Ｂ参照）。
【００６７】
ステップ９１５で、このプロシージャは、引数Ｘおよびｋを伴うＧｅｔＮｅｘｔＨａｎｄｌｅ関数が呼び出され、それによって、ハンドルｈ’およびブールのｉｓＬｉｎｋが返される。前述のように、ブールのｉｓＬｉｎｋは、ハンドルｈ’がノードＸの兄弟へのリンクであるかどうかを示す。ステップ９１６で、このプロシージャは、ｉｓＬｉｎｋが真かどうかテストし、真である場合には、ステップ９１９に向かって分岐する。ｉｓＬｉｎｋが偽である場合には、このプロシージャはステップ９１７に進み、ここでＬＣを減分する。ステップ９１８で、このプロシージャは、ハンドルｈｘをスタックＳ上にプッシュする。ステップ９１９で、この関数は、ｈ’の値をｈｘに割り当てる。
【００６８】
次いで、図９の下位区分図９Ｂを参照すると、ステップ９２０で、このプロシージャは、ハンドルｈｘによって指されるブロックをロックするために、Ｌｏｃｋ（）関数を呼び出す。ステップ９２１で、このプロシージャは、ハンドルｈｘによって識別されたブロックを読み取り、インデックスノードＸおよびバージョン番号ｖを抽出するＲｅａｄ（ｈｘ）を呼び出す。ステップ９２２で、このプロシージャは、ｈｘ．ｖがｖに等しいかどうかテストする。等しくない場合には、図のようにステップ９０６（下位区分図９Ａ）に分岐する。一方、ｈｘ．ｖがｖに等しい場合には、このプロシージャはステップ９２３に進み、ここで関数ＩｓＬｅａｆ（Ｘ）が真かどうかテストする。真でない場合には、このプロシージャは、ステップ９３４（図９の下位区分図９Ｃ）に分岐し、真である場合には、ステップ９２５に進み、ここでＸ．ｋｎ−１がｋ未満であるかどうかテストする。ステップ９２５のテストに対する答が「はい」の場合には、このプロシージャはステップ９３４に分岐し、「いいえ」の場合には、このプロシージャはステップ９２６に進む。ステップ９２６で、このプロシージャは、ｋがＸ．ｋｉ未満であるような最小のｉを見つける。ステップ９２７で、このプロシージャは、ハンドルＸ．ｈｉ＋１によって識別されたブロックを読み取り、データノードＤおよびバージョン番号ｖを抽出するＲｅａｄ（Ｘ．ｈｉ＋１）を呼び出す。ステップ９２８で、このプロシージャは、Ｄ．ｋがｋに等しいかどうかテストし、等しい場合には、このプロシージャはステップ９２９に進み、そうでない場合には、ステップ９３４に分岐する。ステップ９２９で、このプロシージャは、キー値ｋおよびデータ値ｄを含むデータノードとなるようにノードＤを定義する。次に、ステップ９３０で、ノードＤをハンドルｈｉ＋１によって参照されるブロックに書き込むために、関数Ｗｒｉｔｅ（Ｄ，Ｘ．ｈｉ＋１）が呼び出される。次に、ステップ９３１で、ハンドルｈＤによって指されるブロックを割振り解除し、ブロックのバージョン番号を増分するために、関数Ｄｅａｌｌｏｃ（ｈＤ）が呼び出される。ステップ９３２で、ハンドルｈＸによって指されるブロックがロック解除され、次いでステップ９３３で、プロシージャが戻る。
【００６９】
次いで、図９の下位区分図９Ｃを参照すると、ステップ９３４で、このプロシージャは、ｋがＸ．ｋｍｉｎより大きく、かつＸ．ｋｍａｘ以下であるかどうかテストする。ステップ９３４のテストに対する答が「はい」の場合には、このプロシージャはステップ９４１に進み、答が「いいえ」の場合には、このプロシージャはステップ９３５に進む。ステップ９３５で、ハンドルｈＸによって指されるブロックがロック解除され、次いでステップ９３６で、関数ＧｅｔＮｅｘｔＨａｎｄｌｅが引数Ｘ，ｋを伴って呼び出され、それによって、ハンドルｈ’およびブールのｉｓＬｉｎｋを返す。上述のように、この関数は、ハンドルｈ’と、このハンドルがノードＸの兄弟へのリンクかどうかを示すブールのｉｓＬｉｎｋとを返す。ステップ９３７で、このプロシージャは、ｉｓＬｉｎｋが真かどうかテストし、真である場合には、ステップ９３８に進み、真でない場合には、ステップ９２０（図９の下位区分図９Ｂ参照）に分岐する。ステップ９３８で、ハンドルｈＸにｈ’の値が割り当てられ、次いでステップ９３９で、バージョン番号ｖと、ハンドルｈＸによって指されるノードＸとを決定するために、Ｒｅａｄ（ｈＸ）が呼び出される。ステップ９４０で、このプロシージャは、ｈＸ．ｖがｖに等しいかどうかテストし、等しい場合には、図のようにステップ９３６に戻り、等しくない場合には、ステップ９０６（図９の下位区分図９Ａ）に分岐する。
【００７０】
上述のように、ステップ９３４で、このプロシージャは、ｋがＸ．ｋｍｉｎより大きく、かつＸ．ｋｍａｘ以下であるかどうかテストする。このテストに対する答が「はい」の場合には、このプロシージャはステップ９４１に進み、ここで、ノードＸが満杯かどうかテストする。Ｘが満杯である場合には、このプロシージャはステップ９４６（図９の下位区分図９Ｄ）に進み、そうでない場合には、ステップ９４２に進む。ステップ９４２で、このプロシージャは、キーｋおよびハンドルｈＤをノードＸに挿入するために、ＩｎｓｅｒｔＰａｉｒ（Ｘ，ｋ，ｈＤ）を呼び出す。ステップ９４３で、ノードＸをハンドルｈＸによって参照されるブロックに書き込むために、Ｗｒｉｔｅ（Ｘ，ｈＸ）が呼び出される。ステップ９４４で、ハンドルｈＸによって指されるブロックがロック解除され、次いでステップ９４５で、プロシージャが戻る。
【００７１】
次いで、図９の下位区分図９Ｄを参照すると、ノードＸが満杯の場合には、Ｘが２つのノードＸ、Ｙに分割される。ステップ９４６で、このプロシージャは、関数ＩｓＬｅａｆ（Ｘ）が真であるかどうかテストする。真である場合には、このプロシージャはステップ９４７に進み、真でない場合には、このプロシージャはステップ９５１に進む。一方ではステップ９４７、９４８、９４９、他方ではステップ９５１、９５２、９５３は、Ｘがリーフであるか否かに応じて、ノードＹおよびＸを定義するために実行される。ステップ９４７および９５１は、ノードＹを定義するために実行され、ステップ９４８および９５２は、Ｙのための空間を割り振るために実行され、ステップ９４９および９５３は、ノードＸを定義するために実行される。ステップ９５０で、このプロシージャは、Ｘ．ｋｍａｘがキー値ｋ未満であるかどうかテストする。ｋ未満でない場合には、このプロシージャはステップ９５４に進み、ここで、ｋおよびｈＤをＸに挿入するために、引数Ｘ、ｋ、ｈＤを伴って（図５と共に上述した）関数ＩｎｓｅｒｔＰａｉｒが呼び出される。ステップ９５５で、ノードＹを書き込むためにＷｒｉｔｅ（Ｙ，ｈｙ）が呼び出される。同様に、ステップ９５７で、ノードＸを書き込むためにＷｒｉｔｅ（Ｙ，ｈｘ）が呼び出される。ステップ９５０で、Ｘ．ｋｍａｘがｋ未満であると決定された場合には、このプロシージャはステップ９５６に進み、ここで、ｋおよびｈＤをＹに挿入するために関数ＩｎｓｅｒｔＰａｉｒ（Ｙ，ｋ，ｈＤ）が呼び出され、その後、上述のようにステップ９５５および９５７が実行される。ステップ９５８で、Ｒｅａｄ（ｈｐ）が呼び出され、この関数は、バージョン番号ｖと、ハンドルｈｐによって指されるブロック内のプライムノードＰとを返す。
【００７２】
次いで、このプロシージャはステップ９５９に進む（図９の下位区分図９Ｅ参照）。
図９の下位区分図９Ｅを参照すると、ステップ９５９で、このプロシージャは、ハンドルｈｘがプライムノードＰ内の最後のハンドルであり、ｈｘによって識別されたノードがツリーのルートであることを意味するかどうか判定する。最後のハンドルであれば、このプロシージャはステップ９６０から９６６まで進み、最後のハンドルでない場合には、ステップ９６７から９７２まで進む。ステップ９６０で、このプロシージャは、図のようにインデックスノードＺを定義する。ステップ９６１で、Ｚを保持するのに十分な大きさのブロックを割り振り、そのブロックにハンドルを返すために、関数Ａｌｌｏｃ（Ｚのための空間）でハンドルｈｚが定義される。換言すれば、関数Ａｌｌｏｃ（）によってハンドルｈｚが返される。ステップ９６２で、インデックスノードＺをハンドルｈｚによって参照されるブロックに書き込むために、関数Ｗｒｉｔｅ（Ｚ，ｈｚ）が呼び出される。ステップ９６３で、このプロシージャは、ｈｚをプライムノードＰの端部に添付する。ステップ９６４で、ノードＰをハンドルｈｐによって参照されるブロックに書き込むために、Ｗｒｉｔｅ（Ｐ，ｈｐ）が呼び出される。次に、ステップ９６５で、ハンドルｈｘによって指されるブロックがロック解除され、次いで、ステップ９６６で、プロシージャが戻る。
【００７３】
ステップ９５９で、ｈｘがＰ内の最後のハンドルであるかどうかのテストに対する答が「いいえ」である場合には、このプロシージャはステップ９６７に進み、ここで、ハンドルｈｘによって指されるブロックがロック解除される。次いで、ステップ９６８で、ハンドルｈＤがｈＹに設定される。ステップ９６９で、キー値ｋがＸ．ｋｍａｘに設定される。ステップ９７０で、このプロシージャは、スタックＳが空であるかどうか判定し、空でない場合にはステップ９７１に進み、ここで、スタックＳ上の最後の値からハンドルｈｘが定義される。一方、Ｓが空である場合には、このプロシージャはステップ９７３に進み、ここでハンドルｈｘがＰ［ＬＮ］で定義され、次いでステップ９７４で、ＬＮがＬＮ＋１と定義される。最後に、ステップ９７２で、ＬＴがＬＴ＋１に設定され、次いで、図のように、このプロシージャはステップ９２０に戻る（図９の下位区分図９Ｂ参照）。
【００７４】
要するに、図９（下位区分図９Ａから図９Ｅ）のＩｎｓｅｒｔプロシージャは、プライムノードハンドルｈｐ、キー値ｋ、データ値ｄを取り、キー−データ対をｈｐによって識別されたツリーに挿入する。
【００７５】
図１０は、Ｃｏｍｐｒｅｓｓという名称のプロシージャの流れ図である。このプロシージャは、プライムノードハンドルｈｐを取り、そのノードを圧縮し、バックグラウンドプロセスによって実行されるため、返さない。Ｃｏｍｐｒｅｓｓプロシージャ１０００は、呼出しＣｏｍｐｒｅｓｓ（ｈｐ）によりエントリポイント１００２で始まる。ステップ１００４で、Ｒｅａｄ（ｈｐ）が呼び出され、この関数は、バージョン番号ｖと、ハンドルｈｐによって指されるプライムノードＰとを返す。ステップ１００６で、インデックスｉが１に設定される。ステップ１００８で、このプロシージャは、ノードＰ内のハンドルの数がｉより大きいかどうかテストする。Ｐ内のハンドルの数がｉより大きい場合には、このプロシージャはステップ１０１０に進み、引数Ｐ［ｉ］を伴う関数ＣｏｍｐｒｅｓｓＬｅｖｅｌを呼び起こす。この関数については、図１１と共に以下で述べる。手短に言えば、ＣｏｍｐｒｅｓｓＬｅｖｅｌ（）は、インデックスノードハンドルｈＸを取り、そのハンドルによって指されるインデックスノードと、その右兄弟すべてを圧縮した関数である。ステップ１０１２で、インデックスｉがｉ＋１に設定され、次いで、このプロシージャは、判断ステップ１００８に戻る。ステップ１００８で、Ｐ内のハンドルの数がｉより大きくないと決定された場合には、このプロシージャはステップ１０１４に進み、ここで、ハンドルｈがノードＰ内の最後のハンドルに設定される。次に、ステップ１０１６で、ハンドルｈによって指されるブロックがロックされ、次いでステップ１０１８で、Ｒｅａｄ（ｈ）が呼び出され、この関数は、バージョン番号ｖと、ハンドルｈによって指されるノードＸとを返す。次に、ステップ１０２０で、このプロシージャは、Ｎｕｍ（Ｘ）が０に等しく、かつＸ．ｈｒｉｇｈｔがヌルに等しく、かつｎｏｔ  ＩｓＬｅａｆ（Ｘ）がすべて真であるかどうかテストする。そうである場合には、このプロシージャはステップ１０２２に進み、バージョン番号ｖとプライムノードＰを返すＲｅａｄ（ｈｐ）を呼び出す。ステップ１０２０でこのテストに対する答が「いいえ」の場合には、このプロシージャはステップ１０３２に跳び、ハンドルｈによって指されるブロックをロック解除する。ステップ１０２２が実行された後で、このプロシージャはステップ１０２４に移り、ｈがＰ内の最後のハンドルであるかどうか（すなわち、ｈがツリーのルートノードを指しているかどうか）テストされ、最後のハンドルでない場合には、このプロシージャはステップ１０３２に跳び、最後のハンドルである場合には、ステップ１０２６に進む。ステップ１０２６で、このプロシージャは、最後のハンドルをＰから除去し、ステップ１０２８で、ハンドルｈｐによって参照されるノードＰを書き込む。次に、ステップ１０３０で、このプロシージャは、ハンドルｈによって指されるブロックを割振り解除し、次いで、ステップ１０３２に進み、ここで、ハンドルｈによって指されるブロックをロック解除する。最後に、ステップ１０３４で、このプロシージャは休止し、次いで、図のようにステップ１００４に戻る。要するに、このプロシージャは、ハンドルｈｐによって識別されたツリーを圧縮する。
【００７６】
ＣｏｍｐｒｅｓｓＬｅｖｅｌプロシージャ１１００は、呼出しＣｏｍｐｒｅｓｓＬｅｖｅｌ（ｈＸ）によりエントリポイント１１０１で始まる。ステップ１１０２で、変数ａが０に設定され、ステップ１１０３で、ｈＡがヌルに設定される。次に、ステップ１１０４で、このプロシージャは、ハンドルｈＸがヌルであるかどうかテストし、ヌルである場合にはステップ１１０５に進み、ここでプロシージャが戻る。ｈＸがヌルでない場合には、このプロシージャはステップ１１０６に進み、ハンドルｈＸによって指されるブロックをロックする。次に、ステップ１１０７で、Ｒｅａｄ（ｈＸ）が呼び出され、インデックスノードＸとそのバージョン番号ｖを読み取る。ステップ１１０８で、このプロシージャは、ハンドルｈＡがヌルであるかどうかテストする。ｈＡがヌルである場合には、このプロシージャはステップ１１１５（図１１の下位区分図１１Ｂ）に分岐し、ｈＡがヌルでない場合には、このプロシージャはステップ１１０９に進み、ここで変数ａが−１に設定される。次に、ステップ１１１０で、インデックスｉがゼロに設定され、次いでステップ１１１１で、このプロシージャは、Ｎｕｍ（Ｘ）がｉ以上であるかどうか試験する。すなわち、このプロシージャは、関数Ｎｕｍ（Ｘ）によって返された数ｎがインデックスｉ以上であるかどうかテストする。ｉ以上でない場合には、このプロシージャはステップ１１１５（図１１の下位区分図１１Ｂ）に分岐し、ｉ以上である場合には、ステップ１１１２に進む。ステップ１１１２で、このプロシージャは、ノードＸのｉ番目の子へのハンドル（すなわち、Ｘ．ｈｉ）がハンドルｈＡに等しいかどうかテストする。等しくない場合には、このプロシージャはステップ１１１４に進み、インデックスｉを増分し、次いでステップ１１１１に戻る。Ｘ．ｈｉがハンドルｈＡに等しい場合には、このプロシージャはステップ１１１３に進み、ここで変数ａがインデックスｉの値に設定される。
【００７７】
次いで、図１１の下位区分図１１Ｂを参照すると、ステップ１１１５で、このプロシージャは、ハンドルｈＡがヌルであるか、または変数ａが−１にもＮｕｍ（Ｘ）にも等しくないかテストする。ステップ１１１５のテストに対する答が「いいえ」の場合には、このプロシージャは、ステップ１１１６から１１１８まで進み、次いで、図のようにステップ１１０４に戻る。ハンドルｈＸによって指されるブロックをロック解除し、ｈＸをインデックスノードＸのフィールドｈｒｉｇｈｔに設定し、次いで、ハンドルｈＡをヌルに設定するために、ステップ１１１６から１１１８が実行される。
【００７８】
ステップ１１１５のテストに対する答が「はい」の場合には、このプロシージャは、ステップ１１１９で始まる一連のステップを実行し、ステップ１１１９で、ハンドルｈＡがヌルであるかどうかテストする。ｈＡがヌルである場合には、このプロシージャは、ステップ１１２０で変数ａを０に設定する。ハンドルｈＡがヌルでない場合には、このプロシージャは、ステップ１１２２でａを増分する。次いで、ステップ１１２１で、ハンドルｈＡがＸ．ｈａに設定される。ステップ１１２３で、ハンドルｈＡによって指されるブロックがロックされ、次いでステップ１１２４で、インデックスノードＡとその関連バージョン番号ｖを読み取るために、関数Ｒｅａｄ（ｈＡ）が呼び出される。ステップ１１２５で、ハンドルｈＢがＡ．ｈｒｉｇｈｔに設定される。次に、ステップ１１２６で、このプロシージャは、ハンドルｈＢがヌルであるかどうかテストする。ヌルである場合には、ステップ１１３１から１１３３が実行される。すなわち、ハンドルｈＸによって指されるブロックがロック解除され、ハンドルｈＡによって指されるブロックがロック解除され、次いでプロシージャが戻る。一方、ハンドルｈＢがヌルでない場合には、このプロシージャはステップ１１２７に進み、ハンドルｈＢによって指されるブロックをロックする。次に、ステップ１１２８で、バージョン番号ｖとノードＢを決定するためにＲｅａｄ（ｈＢ）が呼び出される。ステップ１１２９で、Ｂ．ｈｌｅｆｔがハンドルｈＡの値に設定される。次に、ステップ１１３０で、ｂが０に設定される。
【００７９】
ＣｏｍｐｒｅｓｓＬｅｖｅｌプロシージャの残りのステップは、図１１の下位区分図１１Ｃに示されている。この下位区分を参照すると、ステップ１１３４で、このプロシージャは、Ｘ．ｈｂがｈＢであるかどうかテストする。ｈＢである場合にはステップ１１４４に進み、そうでない場合には、ステップ１１３５に進む。ステップ１１３５で、変数ｂが増分され、ステップ１１３６で、このプロシージャは、Ｎｕｍ（Ｘ）がｂ以上であるかどうかテストする。ｂ以上である場合には、このプロシージャは、図のようにステップ１１３４に戻る。ｂ以上でない場合には、このプロシージャはステップ１１３７に進み、ハンドルｈＸによって指されるブロックをロック解除する。次に、ステップ１１３８で、このプロシージャは、ハンドルｈＡによって指されるブロックをロック解除し、ステップ１１３９で、ハンドルｈＢによって指されるブロックをロック解除する。ステップ１１４０で、このプロシージャは、Ｂ．ｋｍａｘがＸ．ｋｍａｘ未満であるかどうかテストする。Ｘ．ｋｍａｘ未満でない場合には、このプロシージャは、ハンドルｈＸがＸ．ｈｒｉｇｈｔに設定されるステップ１１４３を実行する。ステップ１１４０で決定され、Ｂ．ｋｍａｘがＸ．ｋｍａｘ未満である場合には、このプロシージャはステップ１１４１に進み、Ｎｕｍ（Ａ）がｔ未満であるか、またはＮｕｍ（Ｂ）がｔ未満であるかテストする。これらのどちらかが真である場合には、このプロシージャはステップ１１４２に進み、ハンドルｈＡをヌルに設定し、次いで、図のようにステップ１１０４（図１１の下位区分図１１Ａ）に戻る。
【００８０】
ステップ１１４４で、このプロシージャは再び、Ｎｕｍ（Ａ）がｔ未満であるか、またはＮｕｍ（Ｂ）がｔ未満であるかテストする。どちらもｔ未満でない場合には、このプロシージャは、図のようにステップ１１５２から１１５４まで進み、そこからステップ１１５０および１１５１に進み、その後、このプロシージャはステップ１１０４（図１１の下位区分図１１Ｂ）に戻る。ステップ１１４４のテストに対する答が「はい」の場合には、このプロシージャは、図のようにステップ１１４５、１１４６、１１４７、１１４８、１１４９に進む（これらのステップは、現時点までに自明であるはずであり、順序正しく実行されないことは自明である）。これらのステップが実行された後で、このプロシージャは、ノードＢが削除されているかどうかテストし、削除されている場合には、ステップ１１０４に戻る。Ｂが削除されていない場合には、このプロシージャは、ステップ１１５１でｈＡをｈＢに設定する。
【００８１】
図１２は、ＭｅｒｇｅＮｏｄｅｓという名称のプロシージャの流れ図である。このプロシージャは、名前が暗示するようにノードをマージする。すなわち、インデックスノードＸ、Ａ、Ｂ（ただし、ＡはＢの左兄弟であり、Ｘはそれらの親である）、および、これらのノードを参照するインデックスノードハンドルｈＸ、ｈＡ、ｈＢを取り、ＡおよびＢの内容をＡにマージし、そのプロセスの中でＢを捨てる。ＭｅｒｇｅＮｏｄｅｓプロシージャ１２００は、図のように、エントリポイント１２０２で始まり、呼出しＭｅｒｇｅＮｏｄｅｓ（Ｘ，Ａ，Ｂ，ｈＸ，ｈＡ，ｈＢ）で呼び出される。ステップ１２０４で、このプロシージャは、ＩｓＬｅａｆ（Ａ）が真であるかどうかテストする。ｘ−ｓＬｅａｆ（Ｘ）が、Ｘ．ｈ０がヌルの場合のみ真を返す関数であることを想起されたい。ＩｓＬｅａｆ（Ａ）が真である場合には、このプロシージャはステップ１２０６を実行し、偽の場合には、このプロシージャはステップ１２１０を実行する。ステップ１２０６および１２１０は、対応するブロック内に示されている値をノードＡに割り当てる。次に、ステップ１２０８で、このプロシージャは、ノードＢに関して示されている動作を実行する。ステップ１２１２で、ノードＸが図のように定義される。次いで、ノードＡ、Ｘ、Ｂを書き込み、ハンドルｈＡ、ｈＸ、ｈＢをロック解除し、ハンドルｈＢによって識別されたインデックスノードＢを割振り解除するために、ステップ１２１４から１２２８が実行される。このプロシージャは、ステップ１２２８で戻る。
【００８２】
図１３は、ＭｏｖｅＴｏＬｅｆｔという名称のプロシージャの流れ図である。このプロシージャは、ノードを左に移動させるために実行され、インデックスノードの内容の一部をその左兄弟に移動するために実行される。ＭｏｖｅＴｏＬｅｆｔプロシージャ１３００は、呼出しＭｏｖｅＴｏＬｅｆｔ（Ｘ，Ａ，Ｂ，ｈＸ，ｈＡ，ｈＢ）によりエントリポイント１３０２で始まる。ステップ１３０４で、変数ｍが１／２Ｎｕｍ（Ｂ）−１／２Ｎｕｍ（Ａ）と定義される。関数Ｎｕｍ（Ｘ）がｎを返し、ただし、Ｘがインデックスノード（hleft, kmin, h0, k0, h1, k1, ..., hn-1, kn-1, hn, kmax, hright）であることを想起されたい。したがって、Ｎｕｍ（Ｘ）は整数ｎを返し、ただしｎは、ノードＸの最後の子のハンドルのインデックスである。
【００８３】
ステップ１３０６で、このプロシージャは、ＩｓＬｅａｆ（Ａ）が真であるかどうか（すなわち、Ａ．ｈ０がヌルであるかどうか）テストする。真である場合には、このプロシージャは、図のようにステップ１３０８および１３１０を実行し、真でない場合には、このプロシージャはステップ１３１４および１３１６を実行する。これらのステップは、対応するブロック内に示されている値をノードＡおよびＢに割り当てる。
【００８４】
ステップ１３１２から１３３０は、インデックスノードＡ、Ｘ、Ｂを書き込み、ロック解除し、次いで戻る。
【００８５】
図１４は、インデックスノードＸ、Ａ、Ｂ、およびインデックスノードハンドルｈＸ、ｈＡ、ｈＢを取るＭｏｖｅＴｏＲｉｇｈｔという名称のプロシージャの流れ図である。ステップ１４０２から１４０６は、１４０４で、変数ｎが１／２Ｎｕｍ（Ｂ）−１／２Ｎｕｍ（Ａ）ではなく１／２Ｎｕｍ（Ａ）＋１／２Ｎｕｍ（Ｂ）と定義されることを除いて、直接、上述したステップ１３０２から１３０６と同様である。プロシージャ１４００の残りのステップは、上述したプロシージャ１３００の対応するステップと同様であるが、右移動関数を実施するために修正される。これらの違いは、当業者には明らかであり、ここでは述べないことにする。
【００８６】
Ｇ．結論
上述のように、本発明の例示的な実施形態について、様々なコンピューティングデバイスおよびネットワークアーキテクチャと共に述べたが、基礎となる概念は、Ｂ−Ｌｉｎｋまたは他のデータ構造をトラバースするのに、かつ／またはＢ−Ｌｉｎｋまたは他のデータ構造と共に他の機能を実行するのに望ましいどのコンピューティングデバイスまたはシステムにも適用することができる。したがって、上述したプロシージャおよびシステムは、様々な応用例およびデバイスに適用することができる。本明細書では、例示的なデータ構造、プログラミング言語、名前、および例が様々な選択の代表として選択されているが、これらは制限しないものとする。
【００８７】
本明細書に述べられている様々な技法は、ハードウェアまたはソフトウェアと、あるいは適切な場合には、双方の組合せと共に実施することができる。したがって、本発明の方法および装置、または本発明のある態様または一部分は、フロッピー（登録商標）ディスク、ＣＤ−ＲＯＭ、ハードドライブ、または任意の他の機械可読記憶媒体など、有形媒体内で実施されるプログラムコード（すなわち、命令）の形態を取ることができ、プログラムコードがコンピュータなどマシンにロードされ、マシンによって実行されたとき、そのマシンは、本発明を実施するための装置になる。プログラム可能なコンピュータ上でプログラムコードを実行する場合には、そのコンピューティングデバイスは一般に、プロセッサ、プロセッサによって読取り可能な（揮発性／不揮発性のメモリおよび／または記憶要素を含む）記憶媒体、少なくとも１つの入力デバイス、および、少なくとも１つの出力デバイスを含む。たとえばデータ処理用ＡＰＩなどの使用を介して本発明のデバッグ用インターフェース態様を使用することができる１つまたは複数のプログラムは、コンピュータシステムと通信するために、上位手続き型またはオブジェクト指向型プログラミング言語の形で実施されることが好ましい。しかし、望むなら、プログラム（群）をアセンブリ言語または機械語で実施することができる。どのような場合でも、言語は、コンパイラ言語またはインタプリタ言語とすること、またハードウェア実装と組み合わせることができる。
【００８８】
本発明の方法および装置は、電気配線またはケーブルを介して、光ファイバを介して、または任意の他の形態の伝送を介してなど、何らかの伝送媒体を介して伝送されるプログラムコードの形態で実施される通信を介して実施することができ、このプログラムコードは、ゲートアレイ、プログラム可能な論理デバイス（ＰＬＤ）、クライアントコンピュータなど、マシンによって受信され、マシン内にロードされ、実行される。このプログラムコードは、汎用プロセッサ上で実施されたとき、プロセッサとあいまって、本発明の機能を呼び出すように動作する独自の装置を提供する。さらに、本発明と共に使用される記憶技法は、常にハードウェアとソフトウェアの組合せとすることができる。
【００８９】
以上、本発明について現在好ましい実施形態と共に述べたが、本発明の同じ機能を実行するために、本発明から逸脱することなしに、他の同様な実施形態を使用することができ、または、上述の実施形態に修正または追加を加えることができることを理解されたい。たとえば、当業者なら、本明細書に述べられている本発明を、有線であろうと無線であろうと、任意のコンピューティングデバイスまたは環境に適用することができること、また、通信ネットワークを介して接続され、そのネットワークを跨いで相互作用する任意の数のそのようなコンピューティングデバイスに適用することができることを理解するであろう。さらに、特に無線でネットワーク化されたデバイスの数が急増し続けているので、ハンドヘルドデバイス用オペレーティングシステム、および他の特定用途向けオペレーティングシステムを含む様々なコンピュータプラットフォームが企図されていることを強調すべきである。さらに、本発明は、複数の処理用チップまたはデバイス内で、またはそれらを跨いで実施することができ、同様に、複数のデバイスを跨いで記憶を実施することができる。したがって、本発明は、どの単一の実施形態にも限定するべきでなく、むしろ添付の特許請求の範囲の広さと範囲内で解釈するべきである。
【図面の簡単な説明】
【００９０】
【図１】本発明に適した例示的なコンピューティング環境の概略図である。
【図２】本発明に適した例示的なコンピューティング環境の概略図であり、（それだけには限らないが）データベースなど持続性ストア内に記憶されたＢ−リンク−ツリーデータ構造の一例を示す。
【図３Ａ】従来技術によるＢ−リンク−ツリーの単純化された概略図である。
【図３Ｂ】本発明の一態様によるＢ−リンク−ツリーの概略図である。
【図３Ｃ】従来技術によるＳａｇｉｖ式Ｂ−リンク−ツリーの例の図である（下記の考察参照）。
【図３Ｄ】本発明による左リンクを含むＢ−リンク−ツリーの例の図である。
【図３Ｅ】左兄弟へのリンクを使用するＬｏｏｋｕｐプロシージャのための擬似コードの例の図である。
【図３Ｆ】バージョン番号を使用するＬｏｏｋｕｐプロシージャのための擬似コードの例の図である。
【図４】プロシージャＧｅｔＮｅｘｔＨａｎｄｌｅの流れ図であり、このプロシージャは、インデックスノードＸとキーｋを取り、（ｈ，ｉｓＬｉｎｋ）を返し、ただしｈはハンドルであり、ｉｓＬｉｎｋは、ｈがＸの兄弟へのリンクであるかどうかを示すブール値である。
【図５】インデックスノードＸ、キーｋ、ハンドルｈを取り、キー−ハンドル対をＸに挿入するプロシージャＩｎｓｅｒｔＰａｉｒの流れ図である。
【図６】新しいツリーを識別するプライムノードハンドルｈｐを返すプロシージャＣｒｅａｔｅＴｒｅｅの流れ図である。
【図７】プライムノードハンドルｈｐおよびキーｋを取り、データアイテムｄまたはヌルを返すプロシージャＬｏｏｋｕｐの流れ図である。
【図８】プライムノードハンドルｈｐおよびキーｋを取り、ｈｐによって識別されたツリーからキーとその関連データ値を削除するプロシージャＤｅｌｅｔｅの流れ図である。
【図９Ａ】プライムノードハンドルｈｐ、キー値ｋ、データ値ｄを取り、ｈｐによって識別されたツリーにキー値とデータ値を挿入するプロシージャＩｎｓｅｒｔの流れ図である。
【図９Ｂ】プライムノードハンドルｈｐ、キー値ｋ、データ値ｄを取り、ｈｐによって識別されたツリーにキー値とデータ値を挿入するプロシージャＩｎｓｅｒｔの流れ図である。
【図９Ｃ】プライムノードハンドルｈｐ、キー値ｋ、データ値ｄを取り、ｈｐによって識別されたツリーにキー値とデータ値を挿入するプロシージャＩｎｓｅｒｔの流れ図である。
【図９Ｄ】プライムノードハンドルｈｐ、キー値ｋ、データ値ｄを取り、ｈｐによって識別されたツリーにキー値とデータ値を挿入するプロシージャＩｎｓｅｒｔの流れ図である。
【図９Ｅ】プライムノードハンドルｈｐ、キー値ｋ、データ値ｄを取り、ｈｐによって識別されたツリーにキー値とデータ値を挿入するプロシージャＩｎｓｅｒｔの流れ図である。
【図１０】プライムノードハンドルｈｐを取り、ｈｐによって識別されたツリーを圧縮するバックグラウンドプロシージャＣｏｍｐｒｅｓｓの流れ図である。
【図１１Ａ】あるレベルを圧縮するプロシージャＣｏｍｐｒｅｓｓＬｅｖｅｌの流れ図である。
【図１１Ｂ】あるレベルを圧縮するプロシージャＣｏｍｐｒｅｓｓＬｅｖｅｌの流れ図である。
【図１１Ｃ】あるレベルを圧縮するプロシージャＣｏｍｐｒｅｓｓＬｅｖｅｌの流れ図である。
【図１２】２つのノードをマージするプロシージャＭｅｒｇｅＮｏｄｅｓの流れ図である。
【図１３】ノードの一部をその左兄弟に移動するプロシージャＭｏｖｅＴｏＬｅｆｔの流れ図である。
【図１４】ノードの一部をその右兄弟に移動するプロシージャＭｏｖｅＴｏＲｉｇｈｔの流れ図である。
【符号の説明】
【００９１】
１００  コンピューティングシステム環境
１１０  コンピュータ
１２０  処理装置
１３０  システムメモリ
１２１  システムバス
１３１  ＲＯＭ
１３２  ＲＡＭ
１３３  基本入出力システム（ＢＩＯＳ）
１３４  オペレーティングシステム
１３５  アプリケーションプログラム
１３６  他のプログラムモジュール
１３７  プログラムデータ
１４０  インターフェース
１４１  ハードディスクドライブ
１４４  オペレーティングシステム
１４５  アプリケーションプログラム
１４６  他のプログラムモジュール
１４７  プログラムデータ
１５０  インターフェース
１５１  磁気ディスクドライブ
１５２  取外し式の不揮発性磁気ディスク
１５５  光ディスクドライブ
１５６  取外し式の不揮発性光ディスク
１６０  ユーザ入力インターフェース
１６１  ポインティングデバイス
１６２  キーボード
１７０  ネットワークインターフェースまたはアダプタ
１７１  ローカルエリアネットワーク（ＬＡＮ）
１７２  モデム
１７３  広域ネットワーク（ＷＡＮ）
１８０  リモートコンピュータ
１８１  メモリ記憶デバイス
１８５  リモートアプリケーションプログラム
１９０  ビデオインターフェース
１９１  モニタ
１９５  出力周辺機器インターフェース
１９６  プリンタ
１９７  スピーカ
２００  情報検索システム
２０２  サーバ
２０４  データベース
２１０  アロケータ
２０６  Ｂ−リンク−ツリー
３００  Ｂ−リンクツリー
３０２  右リンク
３０４  データノード
３０６  インデックスノード
３１０  左リンク
【図１】
2004185617.tif 000004
【図２】
2004185617.tif 000005
【図３Ａ】
2004185617.tif 000006
【図３Ｂ】
2004185617.tif 000007
【図３Ｃ】
2004185617.tif 000008
【図３Ｄ】
2004185617.tif 000009
【図３Ｅ】
2004185617.tif 000010
【図３Ｆ】
2004185617.tif 000011
【図４】
2004185617.tif 000012
【図５】
2004185617.tif 000013
【図６】
2004185617.tif 000014
【図７】
2004185617.tif 000015
【図８】
2004185617.tif 000016
【図９Ａ】
2004185617.tif 000017
【図９Ｂ】
2004185617.tif 000018
【図９Ｃ】
2004185617.tif 000019
【図９Ｄ】
2004185617.tif 000020
【図９Ｅ】
2004185617.tif 000021
【図１０】
2004185617.tif 000022
【図１１Ａ】
2004185617.tif 000023
【図１１Ｂ】
2004185617.tif 000024
【図１１Ｃ】
2004185617.tif 000025
【図１２】
2004185617.tif 000026
【図１３】
2004185617.tif 000027
【図１４】
2004185617.tif 000028
【外国語明細書】
2004185617.tif 000029
2004185617.tif 000030
2004185617.tif 000031
2004185617.tif 000032
2004185617.tif 000033
2004185617.tif 000034
2004185617.tif 000035
2004185617.tif 000036
2004185617.tif 000037
2004185617.tif 000038
2004185617.tif 000039
2004185617.tif 000040
2004185617.tif 000041
2004185617.tif 000042
2004185617.tif 000043
2004185617.tif 000044
2004185617.tif 000045
2004185617.tif 000046
2004185617.tif 000047
2004185617.tif 000048
2004185617.tif 000049
2004185617.tif 000050
2004185617.tif 000051
2004185617.tif 000052
2004185617.tif 000053
2004185617.tif 000054
2004185617.tif 000055
2004185617.tif 000056
2004185617.tif 000057
2004185617.tif 000058
2004185617.tif 000059
2004185617.tif 000060
2004185617.tif 000061
2004185617.tif 000062
2004185617.tif 000063
2004185617.tif 000064
2004185617.tif 000065
2004185617.tif 000066
2004185617.tif 000067
2004185617.tif 000068
2004185617.tif 000069
2004185617.tif 000070
2004185617.tif 000071
2004185617.tif 000072
2004185617.tif 000073
2004185617.tif 000074
2004185617.tif 000075
2004185617.tif 000076
2004185617.tif 000077
2004185617.tif 000078
2004185617.tif 000079
2004185617.tif 000080
2004185617.tif 000081
2004185617.tif 000082
2004185617.tif 000083
2004185617.tif 000084
2004185617.tif 000085
2004185617.tif 000086
2004185617.tif 000087
2004185617.tif 000088