1996年に発売されたSilicon Graphicsの「Origin 2000サーバ」は、ディレクトリベースのコヒーレンス制御を使う最初の商用サーバで、シングルコアCPU 2ソケットからなる計算ノードを最大512ノードまで接続可能な設計となっていた。そして、データを格納するメインメモリに加えてディレクトリを格納するメモリを持っていた。なお、実際に商品化されたOrigin 2000は最大128ノード接続のもので、256ノード、512ノードのものは作られなかったと言われている。
Origin 2000の輸出ディレクトリは基本的にはビットマップであるが、ノード全体を8グループに分け、すべての輸出先が同一グループに入っている場合は、1ノード/ビットのビットマップとグループ番号を記憶し、輸出先が複数のグループにまたがる場合は、8ノード/ビットの粗いビットマップを用いるという方法で、ディレクトリに必要なメモリを節約している。ただし、粗いビットマップの場合は、1ビットが8ノードを代表しており、その中の1ノードしかデータを輸出していない場合でも、8ノード全部にススヌープを行う必要があり、性能とメモリ量のトレードオフとなる。
メモリのブロックごとにディレクトリエントリを持つと、メモリ容量に比例してディレクトリを格納するメモリ量が増えてしまう。このため、図6.5のように、計算ノード群とメモリとの間にL3キャッシュ(L3$)を設け、L3$にディレクトリを設けるという構成が考えられた。
この構成では、コアのキャッシュをミスしたメモリアクセスはL3$を参照し、L3$もミスした場合はメモリをアクセスしてデータを読み出して要求元のコアに送る(輸出)が、それと同時にディレクトリエントリに要求元のコア番号を記憶する。また、L3$にヒットした場合も、そのアクセスがこれまで記憶していないコアの場合は、そのキャッシュラインを輸出し、コア番号をディレクトリに記憶する。このようにすれば、どのコアのキャッシュにコピーがある(他のデータを格納するためにコアのキャシュから追い出される場合があり、そのデータがメモリから読んだままであれば上書きされてしまうので、過去には輸出されたが、もうそのデータはコアのキャッシュには存在しないということもあり得るが)かが分かり、それらのコアだけにスヌープを送れば良い。
問題はL3$からキャッシュラインが追い出される場合で、その場合、メモリから読んだ状態からデータが書き変えられていればメモリに書き戻されるが、ディレクトリの内容は書き出すメモリが無いので消すことになる。そうなると、ディレクトリを見て該当するコアだけにスヌープを送るということは出来なくなってしまう。このため、L3$からのキャッシュラインの追い出しに際して、そのキャッシュラインが輸出された全コアにスヌープを送り無効化(Invalidate)を行い、輸出先が無い状態にする必要がある。
このL3$とディレクトリ(図ではDirと表記)は1カ所にまとまっている必要は無く、図6.6のようにそれぞれのDIMMチャネルごとにメモリブロックアドレスをインタリーブしている場合は、分散して持つというようにしても良い。
なお、図6.6の構造では、各コアがメモリをアクセスする場合には、そのアドレスが偶数アドレスのメモリブロックか、奇数アドレスのメモリブロックかで要求の送り先を区別しなければならない。
この形をさらに進めると、図6.7に示すように各ノードにL3$とディレクトリを持つというように分散させることもできる。
図6.7の構造では、各ノードはメインメモリの(この図の場合は16ノードであるので)1/16の領域のホームノードとなり、そのアドレスのメモリアクセスは、必ずホームノードを経由して行うことにする。このようにすれば、図6.6のケースと同じで、ホームノードは分担範囲のアドレスのメモリへの全コアからのアクセスを処理して、輸出ディレクトリの状態を正しく保つことができる。
図6.7の構造でコアがメモリへのReadアクセスを行う場合は、アクセス要求パケットをホームノードに送る。要求を受け取ったホームノードはパケットから要求元のコア番号、R/Wの区別やアドレスなどの情報を取り出し、そのアドレスのデータがL3$に有れば、それを読み出して応答パケットを作り、要求元のコアに送り返す。同時に、ホームノードは、輸出ディレクトリに要求元のコア番号を書き込む。
一方、L3$をミスした場合は、ホームノードは、この例では偶数か奇数のメモリブロックを担当するメモリコントローラにメモリアクセスを要求するパケットを送り、メモリからデータを受け取る。
コアのアクセスがWriteの場合は、アクセス要求をホームノードに送るのは同じであるが、他のコアがそのキャッシュラインのデータを持っている場合は、書き込みに先立って無効化(Invalidate)する必要がある。このため、ホームノードはディレクトリを見て、輸出先のコア番号を知り、それらのコアにInvalidate要求を送る。
そして、Invalidateが終わったコアは、ACKパケットをホームノードに送り返す。ホームノードはInvalidate要求を送ったすべてのコアからのACKパケットが受け取られると、L3$にWriteデータを書き込み、ディレクトリには要求元のコアだけが輸出先と書き込む。そしてホームノードは要求元にWriteの完了パケットを送り返す。Writeの完了パケットを受け取った要求元のコアは、自分のL1$、L2$にWriteデータを書き込み、これでWrite動作が完了する。