1

こんにちは、私はそのようなコードを持っていると想像してください:

0. void someFunction()
1. { 
2.  ...
3.  if(x>5)
4.    doSmth();
5. 
6.   writeDataToCard(handle, data1);
7. 
8.   writeDataToCard(handle, data2);
9.
10.  incrementDataOnCard(handle, data);
11. }

事は次のとおりです。手順 6 と 8 が実行された後、誰かがカードを削除したと言うと、操作 10 は正常に完了しません。しかし、これは私のシステムのバグになります。つまり、6 と 8 が実行された場合は、10 も実行する必要があります。このような状況に対処するにはどうすればよいですか?

簡単な要約: ステップ 8 の後で、誰かが私の物理カードを取り外す可能性があります。つまり、ステップ 10 に到達することはなく、システムに問題が発生する可能性があります。つまり、カードは不完全なデータで初期化されます。

4

5 に答える 5

2

取引が中断された場合、カードは障害状態になります。次の 3 つのオプションがあります。

  1. 何もしない。カードは障害状態にあり、そのまま残ります。カードで遊ばないようにユーザーにアドバイスします。カードは、完全なクリーンまたはフォーマットの対象となります。
  2. 次回カードが利用可能になったときにトランザクションをロールバックします。ロールバックを実行するには、カードや中央リポジトリに関する十分な情報が必要です。
  3. 次回カードが利用可能になったときに取引を完了してください。補完を実行するには、カードおよび/または中央リポジトリに関する十分な情報が必要です。

3 つのケースすべてにおいて、進行中の取引を示すフラグをカードに付ける必要があります。

于 2013-09-30T15:03:36.403 に答える
2

ある種のプロトコルを作成する必要があります。たとえば、完了する操作のリストをカードに書き込みます。

  1. Step6、Step8、Step10

タスクを完了すると、リストからエントリが削除されます。

ディスクからデータを再読み込みするときは、リストにエントリが残っていないかどうかを確認します。その場合、操作は以前に正常に完了していないため、以前の状態を復元します。

ユーザーがカードを取り外すのを物理的に防ぐことができない限り、他に方法はありません。

于 2013-09-30T14:53:55.797 に答える
0

それだけではありません:

  • データを temporary_data にコピーします。
  • temporary_data に書き込みます。
  • temporary_data をインクリメントします。
  • データの名前を old_data に変更します。
  • temporary_data の名前を data に変更します。
  • old_data を削除します。

2 つの名前変更ステップで競合状態 (幸運なユーザーがカードを削除した場合) は引き続き発生しますが、データまたは一時データを復元する可能性があります。

于 2013-09-30T15:52:20.987 に答える
0

何をインクリメントしているか (またはその理由)、またはデータがどのように構造化されているかについては述べていません (おそらく、書いているものとインクリメントしているものの間に何らかの関係がありwriteDataToCardます)。

そのため、データに固有の巧妙な手法があるかもしれませんが、続けるには十分ではありません. 代わりに、明らかな汎用手法を次に示します。

  1. おそらく機能する可能性のある最も簡単なこと-フルカードのコミットまたはロールバック

    すべてのデータの 2 つのコピー (正常データとダーティなデータ) を保持します。最下位アドレスにある 1 バイトで、どれが現在適切なアドレスであるかを判断するのに十分です (これは基本的に、サイズ 2 の配列へのインデックスです)。

    新しいデータをダーティ エリアに書き込み、それが完了したら、インデックス バイトを更新します (クリーンとダーティを入れ替えます)。

    インデックスが更新され、新しいデータがすべて正常であるか、またはカードが引き抜かれ、以前のクリーン コピーがまだアクティブになっています。

    プロ- とても簡単です

    コン- ストレージスペースのちょうど半分を浪費していて、何かを変更するときは完全に新しいコピーをダーティエリアに書き込む必要があります。これが問題であるかどうかを判断するのに十分な情報が提供されていません。

  2. ... より少ないスペースを使用するようになりました ... -より小さいサブセットをコミットまたはロールバックします

    ストレージの 50% を無駄にできない場合は、データを独立したチャンクに分割し、それぞれを個別にバージョン管理ます。これで、最大の単一のチャンクを複製するのに十分なスペースだけが必要になりますが、単純なインデックスの代わりに、各チャンクのオフセットまたはポインターが必要になります。

    プロ- まだかなりシンプル

    短所- チャンク間の依存関係を処理できず、分離する必要があります

  3. ジャーナリング

    RedX の回答によると、これは整合性を維持するために多くのファイルシステムで使用されています。

    プロ- これは堅実な手法であり、既存のファイルシステムのドキュメントとリファレンス実装を見つけることができます

    短所- あなたは最新のファイルシステムを書いたばかりです。これは本当にあなたが望んでいたものですか?

于 2013-09-30T16:28:15.723 に答える
0

これに答えるには、より詳細な情報が必要です。

ただし、いくつかの仮定を立てて、2つの可能な解決策を提案します(さらに多くの可能性があります...)。書き込み操作は永続的であると想定しています-したがって、カードを取り外して再挿入した後もカードに書き込まれたデータは残っており、関数呼び出しを実行するプログラムの状態ではなく、カード上のデータの一貫性を参照しています。また、インクリメント メソッドは既に書き込まれたデータをインクリメントし、システムは一貫性を保証するためにこの操作を実行する必要があると仮定します。

  1. 書き込まれたレコードごとに、レコードの状態を示す別のデータ要素 (カード上) を維持します。この状態は、writeData 操作を実行する前に、何か ("WRITING" 状態など) に初期化されます。この状態は、incrementData 操作が (正常に) 実行された後、"WRITTEN" に設定されます。カードから読み取る場合、最初にこの状態をチェックし、WRITTEN でない場合はレコードを無視 (または削除) します。

  2. もう 1 つのオプションは、カードに 2 つの (永続的な) カウンターを維持することです。1 つは書き込みを開始したレコードの数をカウントし、もう 1 つは書き込みを終了したレコードの数をカウントします。書き込みを実行する前に 1 番目をインクリメントし、incrementData 呼び出しを (正常に) 実行した後に 2 番目をインクリメントします。後でカードから読み取るときに、レコードが実際に有効かどうか、または破棄する必要があるかどうかを簡単に確認できます。このオプションは、書き込まれたレコードがなんらかの順序付けまたは索引付けされている場合に有効であるため、カウンターを確認するだけで、有効なレコードとその数を確認できます。これには、任意の数のレコードに対して 2 つのカウンターしか必要としないという利点があります (オプション 1 の各レコードに対して 1 つの状態と比較して)。

ホスト (ソフトウェア) 側では、書き込みを開始する前にカードが使用可能であることを確認する必要があります (存在しない場合は書き込みを行わないでください)。incrementData op の後でカードが取り外されたことを検出した場合は、カードが再挿入されたことを検出した後、または別の書き込みを行う前に、物事を整理する (未完了のレコードを削除し、カウンターを更新する) 必要があります。このためには、ソフトウェア側で状態情報を維持する必要があります。

繰り返しますが、ソリューションのタイプ (さらに多くのソリューションの中から) は、正確なシステムと要件によって異なります。

于 2013-09-30T15:18:28.363 に答える