22

私は、実行時に「オブジェクト モデル」を変更して、トランザクションを透過的に実行できるようにするバイトコード エンハンサーを少なくとも 2 つ知っています。そのうちの 1 つは、私が毎日仕事で使用している Versant VOD の一部であり、もう 1 つは Terracotta の一部です。たとえばORMなど、他にもかなりの数があると思いますが、私の会社ではVersantがそれを処理しています。

私の質問は、設計された製品とは関係なく、それ自体で使用できるオープンソース API はありますか? 「ハッキング可能な」API と言えます。コードを大幅に遅くする読み取りアクセスではなく、変更のみを追跡する必要があります。言い換えれば、明示的な読み取り/書き込みロックを必要とすべきではありません。これには、データ モデルだけでなく、変更を実行するすべてのクラスへのアクセスが必要になるか、比較を行うためにメモリ内に何らかの形式の「前のバージョン」を保持する必要があります。

私が解決しようとしている問題は、(NoSQL) DB で「シリアル化」された「大きな」(32K から 256K) オブジェクト グラフがあることです。それらは長寿命であり、変更の「履歴」を保持するために定期的に再シリアル化する必要があります。ただし、シリアル化にはかなりのコストがかかり、ほとんどの変更はマイナーです。

毎回それらを完全にシリアライズし、ストリームでバイナリ差分を実行することはできましたが、CPU を非常に集中的に使用しているように思えます。より良い解決策は、モデルの書き込み操作を変更して変更をプロトコル化する API です。これにより、最初の「イメージ」が保存された後、プロトコルのみを保存する必要があります。

オブジェクトを比較するために Apache Commons Beanutils について話している質問をいくつか見つけましたが、それはインプレース変更には役に立ちません。すべての「ビジネス トランザクション」の間にモデルの完全なクローンを作成する必要があります。

繰り返しますが、私は同じ JVM 内で、外部サーバー アプリケーションを一切使用しない「インメモリ」API を探しています。ネイティブ コードを含む API は、Win、Mac、Linux で使用できる場合は問題ありません。API は現在、個別にパッケージ化する必要はありません。「親プロジェクト」からそれを抽出して、独立した API を形成できる必要があります (親プロジェクトのライセンスでこれが許可されている必要があります)。

オブジェクト グラフには多くの大きな配列が含まれるため、効率的にサポートする必要があります。

変更は、監査のためだけではなく、再生または元に戻すことができるようにするために必要です。より正確には、デシリアライズされた初期グラフと変更のリストを使用して、同一の最終グラフに到達する必要があります。また、終了グラフから始めて、変更を逆に適用することで最初のグラフに戻ることができるはずです。これはまったく同じ機能を使用しますが、変更プロトコルが新しい値に加えて古い値を保持する必要があります。

API ライセンスは、商用利用と互換性がある必要があります。

[編集] これまでのところ、有用な回答が得られていません。私が望むものが存在するようには見えません。残された選択肢は 1 つだけです。それを実現することです。これは私のプロジェクトの次のステップであり、それなしでは先に進むことができないため、実装が機能するようになったら、ここにリンクを回答として投稿します。

[編集] このやや関連する質問を偶然見つけました: Is there a Java library that can "diff" two Objects?

4

4 に答える 4

8

Kryo v1 には、シリアル化された最後のデータを認識し、デルタのみを発行するシリアライザーがありました。読み取り時に、最後に受信したデータを認識し、デルタを適用します。デルタはバイト レベルで行われます。ここにシリアライザがあります。ほとんどの作業はこのクラスによって行われます。これは、Quake 3 に似たネットワーキングなど、いくつかの便利な方法で使用できます。

これは Kryo v2 では省略されていました。また、広範なテストセットもありませんでした。ただし、移植することもできますし、必要なことを実行したり、必要なものの基礎として機能したりすることもできます。

上記も JVM serializers mailing listに投稿されました。

オブジェクト レベルでそれを行うのは、少し注意が必要です。2 つのオブジェクト グラフを同時に処理するFieldSerializerに似たものを作成できますが、これはスタンドアロン コードであり、Kryo シリアライザーではありません。各レベルで、同等と呼ぶことができます。読み取ったときに等しいかどうかがわかるように、バイトを書き込みます。等しくない場合は、Kryo を使用してオブジェクトを書き込みます。Equals は、特に深くネストされたオブジェクトの場合、同じオブジェクトに対して何度も呼び出されます。

別の方法として、スカラーと文字列に対してのみ、つまり Output クラスによって書き込まれた値に対してのみ上記を行うこともできます。問題は、2 つのオブジェクト グラフを歩くことです。Kryo を使用するには、他のオブジェクト グラフについて知るために、すべてのシリアライザーを複製する必要があると思います。

おそらく、値を書き込む代わりにリストに値を収集する独自の出力で Kryo を使用できます。これを使用して、古いオブジェクト グラフを「シリアル化」します。次に、このリストを取得する独自の出力の別のバージョンを作成し、それを使用して新しいオブジェクト グラフをシリアル化します。値が書き込まれるたびに、まずリスト内の次のオブジェクトでそれをチェックします。等しい場合は 1 を書き込みます。等しくない場合は 0 を書き込み、次に値を書き込みます。

これは、最初の出力を 2 回 (古いグラフで 1 回、新しいグラフで 1 回) 使用することで、スペース効率を高めることができます。これで、2 つの値リストができました。これらを使用して、どちらが等しいかを示すビット文字列を書き込みます。これにより、値ごとにバイト全体を書き込むよりもスペースが節約されますが、余分なリストのオーバーヘッドがあります。最後に、等しくない値をすべて書きます。

このアイデアを完成させるには、データを逆シリアル化できる必要があります。古いオブジェクト グラフから値のリストを取得する独自のバージョンの Input クラスが必要になります。入力は最初にビット文字列 (または値ごとに 1 バイト) を読み取ります。等しい値の場合、データから読み取るのではなく、リストから値を返します。値が等しくない場合は、スーパー メソッドを呼び出してデータから読み取ります。

これがバイトレベルで行うよりも速いかどうかはわかりません。私が推測しなければならないとしたら、おそらくそれはより速いと思います。すべての値をリストに格納すると、多くのボックス化/ボックス化解除が必要になります。このアプローチでは、フィールドが変更されていない場合でも、すべてのフィールドが割り当てられます。どちらの方法でもパフォーマンスが問題になるとは思えないので、おそらく簡単な方法を選択するだけです。それがどれであるかを言うのは難しいです...デルタのものを復活させるか、独自の出力/入力クラスを作成してください。

Kryo に貢献したいという気持ちがあれば、それはもちろん素晴らしいことです。:)

于 2012-05-10T21:10:38.393 に答える
2

Content repository API for Javaを見てください。 Artifactory が Maven の依存関係を制御するために使用します。Apache Jackrabbitは、この JSR ( JSR-283 バージョン 2 )の参照実装です。

于 2012-05-11T02:04:54.537 に答える
1

私の知る限り、GemFire は Gemstone (現在は VmWare) のエンタープライズ製品で、Gemstone の smalltalk OODB に似た機能を備えていますが、Java 向けです。James Foster は、Gemstone がどのように機能するかについての一連のビデオを作成しました。とても興味深いと思いました。Gemstone には、小規模な (Seaside Web) システムを構築するための無料バージョンがあります。

于 2012-05-10T19:16:51.627 に答える
1

私はそのようなAPIを知りませんが、それほど複雑ではありません:

より良い解決策は、モデルの書き込み操作を変更して変更をプロトコル化する API です。これにより、最初の「イメージ」が保存された後、プロトコルのみを保存する必要があります。

必要なコンポーネントは、Action と ActionProcessor の 2 つだけです。

実行されたアクションのリスト (プロトコル) を保持するだけで済みます。

interface ActionProcessor{
    void perform(Action action);
    void undoToDate(Date date);
} 

iterface Action{
    Date getDate();
    void perform();
    void undo();
}      
于 2012-05-09T16:54:39.470 に答える