リポジトリの整合性に問題があるときにオフライン圧縮を実行すると、処理が SegmentNotFoundException で失敗することがあります。

問題点

リポジトリの整合性に問題があるときにオフライン圧縮を実行すると、処理が SegmentNotFoundException で失敗することがあります。次のようなスタックトレースがログに含まれる場合があります。

13:51:21.523 [main] ERROR o.a.j.o.p.segment.SegmentTracker - Segment not found: 4d139bc4-150c-4f0a-b82a-40a4e519fe8a. Creation date delta is 4 ms.
org.apache.jackrabbit.oak.plugins.segment.SegmentNotFoundException: Segment 4d139bc4-150c-4f0a-b82a-40a4e519fe8a not found
    at org.apache.jackrabbit.oak.plugins.segment.file.FileStore.readSegment(FileStore.java:855) [oak-run-1.0.22.jar:1.0.22]
    at org.apache.jackrabbit.oak.plugins.segment.SegmentTracker.getSegment(SegmentTracker.java:134) ~[oak-run-1.0.22.jar:1.0.22]
    at org.apache.jackrabbit.oak.plugins.segment.SegmentId.getSegment(SegmentId.java:101) [oak-run-1.0.22.jar:1.0.22]
...
Exception in thread "main" org.apache.jackrabbit.oak.plugins.segment.SegmentNotFoundException: Segment 4d139bc4-150c-4f0a-b82a-40a4e519fe8a not found
    at org.apache.jackrabbit.oak.plugins.segment.file.FileStore.readSegment(FileStore.java:855)
    at org.apache.jackrabbit.oak.plugins.segment.SegmentTracker.getSegment(SegmentTracker.java:134)
    at org.apache.jackrabbit.oak.plugins.segment.SegmentId.getSegment(SegmentId.java:101)
...

または、リポジトリの整合性に問題があるときにオフライン圧縮を実行すると、処理が IllegalArgumentException で失敗することがあります。次のようなスタックトレースがログに含まれる場合があります。

java.lang.IllegalArgumentException
at com.google.common.base.Preconditions.checkArgument(Preconditions.java:77)
at org.apache.jackrabbit.oak.plugins.segment.ListRecord.(ListRecord.java:41)
at org.apache.jackrabbit.oak.plugins.segment.ListRecord.getEntry(ListRecord.java:64)
at org.apache.jackrabbit.oak.plugins.segment.ListRecord.getEntries(ListRecord.java:81)
at org.apache.jackrabbit.oak.plugins.segment.SegmentStream.read(SegmentStream.java:153)
at org.apache.jackrabbit.oak.commons.IOUtils.readFully(IOUtils.java:53)
at org.apache.jackrabbit.oak.plugins.segment.Compactor.getBlobKey(Compactor.java:412)
at org.apache.jackrabbit.oak.plugins.segment.Compactor.compact(Compactor.java:362)
at org.apache.jackrabbit.oak.plugins.segment.Compactor.compact(Compactor.java:321)
at org.apache.jackrabbit.oak.plugins.segment.Compactor.access$500(Compactor.java:54)
at org.apache.jackrabbit.oak.plugins.segment.Compactor$CompactDiff.propertyAdded(Compactor.java:227)
at org.apache.jackrabbit.oak.plugins.segment.CancelableDiff.propertyAdded(CancelableDiff.java:47)
at org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.compareAgainstEmptyState(EmptyNodeState.java:156)
at org.apache.jackrabbit.oak.plugins.segment.SegmentNodeState.compareAgainstBaseState(SegmentNodeState.java:434)
at org.apache.jackrabbit.oak.plugins.segment.Compactor$CompactDiff.diff(Compactor.java:214)
at org.apache.jackrabbit.oak.plugins.segment.Compactor$CompactDiff.childNodeAdded(Compactor.java:263)
at org.apache.jackrabbit.oak.plugins.segment.CancelableDiff.childNodeAdded(CancelableDiff.java:74)
at org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.compareAgainstEmptyState(EmptyNodeState.java:161)
at org.apache.jackrabbit.oak.plugins.segment.SegmentNodeState.compareAgainstBaseState(SegmentNodeState.java:434)
at org.apache.jackrabbit.oak.plugins.segment.Compactor$CompactDiff.diff(Compactor.java:214)
at org.apache.jackrabbit.oak.plugins.segment.Compactor$CompactDiff.childNodeAdded(Compactor.java:263)
at org.apache.jackrabbit.oak.plugins.segment.CancelableDiff.childNodeAdded(CancelableDiff.java:74)
at org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.compareAgainstEmptyState(EmptyNodeState.java:161)
at org.apache.jackrabbit.oak.plugins.segment.SegmentNodeState.compareAgainstBaseState(SegmentNodeState.java:434)
at org.apache.jackrabbit.oak.plugins.segment.Compactor$CompactDiff.diff(Compactor.java:214)
at org.apache.jackrabbit.oak.plugins.segment.Compactor$CompactDiff.childNodeAdded(Compactor.java:263)
at org.apache.jackrabbit.oak.plugins.segment.CancelableDiff.childNodeAdded(CancelableDiff.java:74)
at org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.compareAgainstEmptyState(EmptyNodeState.java:161)
at org.apache.jackrabbit.oak.plugins.segment.SegmentNodeState.compareAgainstBaseState(SegmentNodeState.java:434)
at org.apache.jackrabbit.oak.plugins.segment.Compactor$CompactDiff.diff(Compactor.java:214)
at org.apache.jackrabbit.oak.plugins.segment.Compactor$CompactDiff.childNodeAdded(Compactor.java:263)
at org.apache.jackrabbit.oak.plugins.segment.CancelableDiff.childNodeAdded(CancelableDiff.java:74)

環境

AEM 6.x

原因

SegmentNotFoundException は、圧縮操作でノードを読み取ろうとしたときにセグメントが存在しない場合に返されます。これには様々な根本原因があります。

  1. セグメントが手動操作(例えば、rm -rf /)によって削除された。
  2. セグメントがリビジョンガベージコレクションによって削除された。 
  3. コードのバグが原因でセグメントが見つからない。

リビジョンガベージコレクション(ポイント 2)が原因で問題が発生している場合は、オンライン圧縮を無効にして、他のノードが破損しないようにします。

解決策

 

この状況を解決し、オフライン圧縮を正常に完了するために、いくつかの手順を実行できます。

重要:次の手順を実行する前に、リポジトリの完全バックアップを実行してください。

A. セグメントストアを整合性のある最も新しいリビジョンに戻す。

oak-run の check run-mode を使用すると、セグメントストアの整合性のある最も新しいリビジョンを確認できます。このリビジョンを使用して、破損しているセグメントストアを整合性のある最も新しいリビジョンに手動で戻すことができます。

警告:

この操作を実行すると、システム内のデータが過去の時点にロールバックされます。  システムの変更が失われないようにするには、代わりに次のオプション B を試してください。

check と復元を実行するには:

  1. oak-run jar ファイルを http://repo1.maven.org/maven2/org/apache/jackrabbit/oak-run/ からダウンロードします。

    • AEM 6.0:Oak 1.0.12 以降を使用している場合は、Oak 1.1.8(oak-run-1.1.8.jar)を使用します。Oak バージョンが 1.0.11 以前の場合は、oak-run 1.1.6 を使用します。
    • AEM 6.1:インストールされているバージョンと一致する oak-run 1.2.x バージョンをダウンロードします(/system/console/bundles UI で確認してください)。

    注意:

    oak-run の 1.0.x ブランチバージョンには「check」コマンドが実装されていないので、ここでは 1.1.x ブランチバージョンを使用しています。

  2. AEM を停止します。

  3. 次のコマンドを実行します。

    java -jar oak-run-*.jar check -d1 --bin=-1 -p crx-quickstart/repository/segmentstore/

    このコマンドは、リビジョンを遡って、整合性のあるリビジョンを検出します。

    14:00:30.783 [main] INFO  o.a.j.o.p.s.f.t.ConsistencyChecker - Found latest good revision afdb922d-ba53-4a1b-aa1b-1cb044b535cf:234880

    (ConsistencyChecker が失敗した場合は、次の節に進んでください)

  4. 以下を編集して、リポジトリをこのリビジョンに戻します。

    /crx-quickstart/repository/segmentstore/journal.log

    整合性のある最も新しいリビジョンを含む行より後のすべての行を削除します。リポジトリが戻される日時を知りたい場合は、segmentstore フォルダー内で次のコマンドを実行します(afdb922d-ba53-4a1b-aa1b-1cb044b535cf を journal.log 内の整合性のある最も新しいリビジョンに置き換えてください)。

    find .-type f -name "data*.tar" -exec sh -c "tar -tvf {} |grep afdb922d-ba53-4a1b-aa1b-1cb044b535cf" \; -print

    出力に、このリビジョンのおおよその日時が表示されます。

  5. ./crx-quickstart/repository/segmentstore/*.bak ファイルをすべて削除します。

  6. AEM 6.0 を使用している場合は、残りの手順を実行するために、AEM にインストールされているバージョンと一致する oak-run バージョンをダウンロードします。http://repo1.maven.org/maven2/org/apache/jackrabbit/oak-run/ からダウンロードしてください。

  7. チェックポイントのクリーンアップを実行して、孤立したチェックポイントを削除します。

    java -jar oak-run-*.jar checkpoints ./crx-quickstart/repository/segmentstore rm-unreferenced

  8. 最後に、リポジトリを圧縮します。

    java -jar oak-run-*.jar compact ./crx-quickstart/repository/segmentstore/

B. 破損しているノードを手動で削除する。

TarMK に FileDatastore が設定されていない場合や、バイナリが破損している場合、AEM で次の操作を実行できます。

警告:

次の手順は、パワーユーザー向けです。  破損しているノードを削除するときは、それがシステムノード(/home、/jcr:system など)でないことを確認する必要があります。  また、システムノードの場合は、そのノードを復元できることを確認する必要があります。  ここに記載されている手順について不安がある場合は、AEM カスタマーケアチームにご相談ください。

  1. AEM を停止します。

  2. Oak 実行コンソールを使用し、childCount groovy スクリプトを読み込んで、セグメントストア内の破損しているノードを特定します。

    oak-run コンソールシェルを読み込みます。

    java -jar oak-run-*.jar console crx-quickstart/repository/segmentstore

    次の 2 つのコマンドをシェルで実行してスクリプトを読み込み、実行します。

    :load https://gist.githubusercontent.com/stillalex/e7067bcb86c89bef66c8/raw/d7a5a9b839c3bb0ae5840252022f871fd38374d3/childCount.groovy

    countNodes(session.workingNode)

    次のように、破損しているノードのパスが出力に示されます。

    21:21:42.029 [main] ERROR o.a.j.o.p.segment.SegmentTracker - Segment not found: 63ae05a4-b506-445c-baa2-cfa1b13b6e2f.Creation date delta is 3 ms.
    warning unable to read node /content/dam/test.txt/jcr:content/renditions/original/jcr:content

    場合によっては、問題がバイナリプロパティに関係していて、childCount groovy スクリプトを使用しても破損しているノードを見つけることができないことがあります。  その場合は、代わりに次のコマンドを使用します。このコマンドを使用すると、走査中に検出されたすべてのバイナリの先頭の 1,024 バイトが読み取られます(このコマンドは低速なので、上記のコマンドを実行しても期待される結果が返さない場合にのみ使用してください)。

    countNodes(session.workingNode,true)

  3. rmNodes.groovy を使用して、上記のコマンドの出力に含まれる特定された破損しているノードをすべて削除します。

    oak-run コンソールシェルを読み込みます。

    java -jar oak-run-*.jar console crx-quickstart/repository/segmentstore

    groovy スクリプトを読み込みます。

    :load https://gist.githubusercontent.com/stillalex/43c49af065e3dd1fd5bf/raw/9e726a59f75b46e7b474f7ac763b0888d5a3f0c3/rmNode.groovy

    rmNode コマンドを実行して、破損しているノードを削除します。ここで、/path/to/corrupt/node を、削除する必要のある破損しているノードのパスに置き換えます。

    rmNode(session, "/path/to/corrupt/node")

    ここで、破損しているノードのパスとして、手順 2 で取得したパスを指定します(例:"/content/dam/test.txt/jcr:content/renditions/original/jcr:content/")。

  4. 手順 2 で見つかったすべてのノードに対して手順 3 を繰り返します。

    上記の rmNode コマンドを破損しているパスに対して実行すると、true が返されます。これは、コマンドによってパスが削除されたことを意味します。これらの見つかった 3 つの破損しているパスに対して rmNode コマンドを再実行して、これらのパスを削除します。再度コマンドを実行すると、false が返されます。

    この時点で同じパスがリポジトリに存在する場合は、パッチが適用されたバージョンの oak-run jar(oak-run-1.2.18-NPR-17596)を使用します

    パッチが適用されたバージョンの Oak run Jar の動作

    このバージョンの jar は、圧縮時に読み取り不可能なバイナリをスキップして 0 バイトのバイナリに置き換え、例外とパスを syserr に記録します。この方法で圧縮したリポジトリはノード数を取得するスクリプトの oak-run check に合格します。これで、パッチの適用されていない oak-run を使用してリポジトリを再度圧縮できるようになります。

  5. 次のコマンドを使用してチェックポイントをリストして、チェックポイントをクリーンアップします。複数のチェックポイントがある場合は、それらをクリーンアップします。

    nohup java -Xmx4096m -jar oak-run-1.2.18.jar checkpoints /app/AEM6/author/crx-quickstart/repository/segmentstore rm-all>>nohup.out &

  6. 非同期ノードを削除します[この手順はオプションです。完全なインデックスの再作成を実行する必要がある場合以外は実行しないでください]。

    java -Xmx4096m -jar oak-run-1.2.18.jar console /app/AEM6/author/crx-quickstart/repository/segmentstore


    :load https://gist.githubusercontent.com/stillalex/43c49af065e3dd1fd5bf/raw/9e726a59f75b46e7b474f7ac763b0888d5a3f0c3/rmNode.groovy

    rmNode(session, "/:async")

  7. サーバーを起動し、インデックスの作成が完了するまで待ちます。

  8. AEM を停止します。

  9. オフライン圧縮を実行します。

本作品は Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License によってライセンス許可を受けています。  Twitter™ および Facebook の投稿には、Creative Commons の規約内容は適用されません。

法律上の注意   |   プライバシーポリシー