MVリフレッシュでORA-01435エラー発生
オンプレに配備されているOracleDBからOCI(Oracle Cloud Infrastructure)に構築されたOracleDBに移行する作業中に見つかった問題。
現時点でも根本原因は不明だが回避策はわかったもの。
前提
- 移行元も移行先も、複数のOracleDBインスタンス(正確に言うと、移行先ではインスタンスではなく同一CDB上の複数のPDB)が存在。
- インスタンス同士はDBLINKにより接続されており、片方のインスタンスからもう片方のインスタンスのオブジェクトが参照可能な状態。
- インスタンスAのテーブルはインスタンスBからDBLINKを通じてアクセス可能。
- インスタンスBには多数のMV(マテリアライズドビュー)が存在。
- それらMVの定義内のクエリでインスタンスAのテーブルを参照するものが多数存在。
- 移行元のOracleDBインスタンスでは、検証環境のシステム群(DBのユーザー)の洗い替え(trunkからbranchへの逆マージ)の都度、Masterの役割を持つスキーマをエクスポートし、別名でインポートすることでDBオブジェクトとレコードの洗い替えをする運用が長年行われてきた。
- 移行はDBLINK経由で移行元DBインスタンスを移行先PDBとしてクローンするという手法で実施。
- 移行元インスタンスに存在したユーザースキーマで、移行先PDBでは不要となるユーザースキーマは、クローン後にdrop。
事象
移行先のOracleDBのPDB B(移行元のインスタンスBに相当)側でMVリフレッシュを行ったところ、以下のようなエラーが発生。
行1でエラーが発生しました。:
ORA-01435: ユーザーが存在しません。
ORA-06512: "SYS.DBMS_SNAPSHOT_UTL", 行364
ORA-06512: "SYS.DBMS_SNAPSHOT_UTL", 行446
ORA-06512: "SYS.DBMS_SNAPSHOT", 行2821
ORA-06512: "SYS.DBMS_SNAPSHOT", 行3058
ORA-06512: "SYS.DBMS_SNAPSHOT", 行3017
ORA-06512: 行1
MVの定義情報を引き出して確認すると、このMVの定義で用いされているDBLINKには問題なし。DBLINK定義時に指定される認証情報は正しく、DBLINKにより参照されるユーザースキーマとそのオブジェクトも健在。手でクエリを実行すれば参照は可能。
原因
不明。
ただおそらく「前提」で述べた移行元DBにおける洗い替えの運用により、データディクショナリのデータ不整合が生じている模様。
OCIでAnsible mountがエラーになるケース
直近、OCI(Oracle Cloud Infrastructure)を利用することがあり、その中でAnsibleのmountタスクがエラーになるケースがあったので紹介します。といっても仕事の中でのことだったのと、あれこれ細かな課題対応が続発するなかでのこと。エラー発生時のキャプチャや具体的なエラーメッセージの内容を示せません。
発生条件 ※1
- OCIのDB System(VM/BM)やComputeを利用している。
- mountモジュールで state=mounted を指定してマウントを行おうとしている。※2
※1 他にも条件があるはずです。Googleで検索をしても類似事象を見つけられなかたことからそう推測しています。ひとまず分かったのはここまでです。
※2 mountモジュールに state=mounted を指定していますので、モジュールは指定されたデバイスが指定されたマウントポイントにマウントされていることを確認し、されていなければマウントし、加えて /etc/fstab ファイルにそのマウントの定義情報を書き込んで再起動後もマウントが約束されるようにします。
発生事象
mountモジュールの処理がエラーとなりPlaybookの実行が中断されます。
エラーメッセージとしては /etc/fstab のパースに失敗した云々の内容が出力されます。
fatal: [(hostname)]: FALED! => {"changed": false, "msg": "Error mounting (mount point): mount: /etc/fstab: parse error: ignore entry at line (line number). \nmount: can't find (mount point) in /etc/fstab\n"}
/etc/fstab の内容を確認すると、本来「既存エントリーの次の行に、つまり改行を挟んで、新規エントリーを追加」しなくてはならないところが「既存エントリーの末尾にそのまま、つまり改行なしに、新規エントリーを追加」してしまっている状態。
なるほどこれではパースに失敗するだろうな、仮にこの状態で /etc/fstab に基づきマウントが実行されたら既存エントリーで定義されたマウントも一蓮托生でエラーになるだろうな、という状態です。
ちなみにこの不正な「新規エントリー」部分をvi等で削除したり、「既存エントリー」と「新規エントリー」の間に改行を挿入してやったりしてからPlaybookを再実行すると今度は正常に処理ができます。後者の改行挿入はともかく前者の「一旦消せば次は成功」という動作はちょっと不可思議です。
回避策
mountモジュールのまえにlineinfileモジュールで「先頭に改行文字を持つfstabエントリーを挿入」してしまいました。とても雑な対応ですがこれで後続のmountモジュールは動作するようになりました。
原因
不明。
なんとなくの推測としてはAnsibleのmountモジュールは /etc/fstab ファイルの末尾、既存の最後のエントリーの行末に、改行文字がもともと入っていることを前提にしているのではないか、ところが私が作業していた環境では(何らかの理由で)そうなっておらず、「既存エントリーの直後に、改行なしに、新規エントリーを挿入」ということになったのではないか、──と想像しています。
『Kotlinイン・アクション』を読んでKotlinへの興味が尽きた
- 作者:Dmitry Jemerov,Svetlana Isakova
- 出版社/メーカー: マイナビ出版
- 発売日: 2017/10/31
- メディア: 単行本(ソフトカバー)
最初に言っておきますが、『Kotlinイン・アクション』はいい本です。プログラミング言語Kotlinについて丁寧に紹介しており、言語仕様はもちろんJavaとの統合についてしっかりと説明をしてくれています。さらにこの言語が提供する機能が従来のJavaによる開発であれば苦痛であったことの多くを解消してくれるのも事実です。おまけにベンダーの方針などを念頭に置くならば、Androidアプリ開発でこの言語を選択するのは妥当なものでしょう。この点異論はありません。
ただ本書を読んでいくとKotlinという言語を学ぶモチベーションが萎えていきます。この本を読み進めることで、Kotlinの構文の中にはJavaよりも却ってコード量が増えるものがあったり、同じキーワードを使っていながら機能的に異なっており明らかに他の妥当なキーワードがあると思われるものがあったりと、せっかく新言語として構想されたのに設計が甘いと感じられるところが節々登場します。Kotlinにおけるthisの記載について、Javaと異なる構文を採用していながらJavaと同じかそれ以上に特殊で一貫性を欠いた面倒な構文になっていることに、大変残念な気持ちになりました。Kotlinにおけるキーワードinterfaceが実際の機能に即してみるなら本当はtraitであるべきという点にもがっかりさせられました。Javaにおけるinterfaceはその歴史的な変遷や言語拡張についてのポリシーのために「実際はtrait」になってしまったわけで、過去に準拠する/束縛される言語としての選択ですから、これはもう仕方ない。しかし言語的に新規に構想されたKotlinがこれと同じことをしていることには納得が行きません。
そしてKotlinの構文が「Javaに似ている」とは言っても大小の違いはおびただしくあり、それらの学習コストは消して少なくありません。Kotlinで書かれたコードとJavaで書かれたコードがお互いにアクセスするとき注意しなくてはならないことも多々あるはずです。だからといって「このままJavaでいこう」などと言うつもりもなく、ただ学習コストの発生を前提にしてより生産的なコーディングを目指すならKotlinを学ぶよりはScalaなどを学ぶほうが得るところは大きそう、ということです。