Orion でコンテキストを変更する通常の方法は、特定の値で属性を更新することです。ただし、場合によっては、 既存の属性値で評価される操作を提供する方がよい場合があります。 例を挙げて見てみましょう。
アクセス制御を通過する人の数を測定する属性 count
を持つエンティティ AccessControl1
を考えてみましょう。
コンテキスト・アウェア・アプリケーションは、コンテキストの更新を担当します (たとえば、センサ測定に基づく)。
誰かがアクセスを通過するたびに、アプリケーションは次のことを行う必要があります:
- 属性の値を読み取ります。例:
GET /v2/entities/attrs/count
。値が43であると考えてみましょう - 新しい値を計算します (43 + 1は44です)
- 属性を新しい値で更新します。例:
PUT /v2/entities/attrs/count { "value": 44, "type": "Number" }
要するに、アプリケーションは読み取り、計算、更新を行う必要があるため、複雑さが増します。
複数のコンテキスト・アウェア・アプリケーションが同じコンテキストに同時にアクセスしている場合、問題はさらに
悪化します。たとえば、単一のアクセス・カウントの代わりに、属性 count
を持つ Zone1
があり、どのアクセスに
関係なく、ゾーンに入るすべての人の集計があります (ゾーンに多くのアクセスがあると仮定します)。
アプリケーションAがアクセスの1つを管理し、アプリケーションBが他のアクセスを管理しています。どちらの
アプリケーションも、誰かがそれぞれのアクセスを通過すると、Zone1
の count
属性を更新します。
ほとんどの場合問題はありません:
- 誰かがAによって管理されているアクセスを通過します
- アプリケーションAは、read-calculate-cycle を実行し、
Zone1
のcount
を更新します。更新前の値が43 だったとしましょう。現在、count
値は44です - しばらくすると、誰かがBによって管理されているアクセスを通過します
- アプリケーションBは、read-calculate-cycle を実行し、
Zone1
のcount
を更新します。したがって、count
値は45になります
ただし、両方のアクセス交差イベントが非常に近い時間に発生すると、問題が発生する可能性があります:
- 誰かがアクセスAを通過すると同時に、誰かがアクセスBを通過します
- アプリケーションAはカウント43を読み取ります
- アプリケーションBは、Aが計算および更新する前にカウントを読み取るため、同じ値を取得します43
- アプリケーション43に1足して、44で更新します
- アプリケーションBも同じことを行い、44で更新します
- したがって、カウントは間違ってしまいます。45である必要がありますが、44です!
この種の問題を競合状態と呼びます (アプリケーションAとBでイベントが発生する速度が異なるため)。これは、 Orion 更新演算子機能、特にインクリメント演算子を使用して解決できます。
したがって、両方のアプリケーションは、特定の値 (44や45など) を直接更新する代わりに、次の方法で "increment by 1" (1だけ増加) の更新を送信します:
POST /v2/entities/Zone1/attrs/count
{
"value": { "$inc": 1 },
"type": "Number"
}
同じケースでは次のようになります:
- ある時点で、ゾーン1のカウントは43であり、誰かがアクセスAを通過すると同時に、誰かがアクセスBを 通過します
- アプリケーションAは
count
を{"$ inc":1}
で更新します - アプリケーションBは
count
を{"$ inc":1}
で更新します - Orion は、操作がアトミックに実行されることを保証します。アプリケーションAによって行われた インクリメントが、アプリケーションBによって行われたインクリメントの前に来るか、またはその逆で あるかは関係ありません。結果は同じです:45
したがって、更新演算子は両方の問題を解決します:
- 複雑さ。これで、アプリケーションは読み取り-計算-更新サイクルを実行する必要がなくなります。 演算子を使用して、更新するだけで十分です
- 競合状態。これは、Orion がこれらの操作がコンテキスト属性でアトミックに実行されることを保証するために 解決されます。多くのアプリケーションは、同じコンテキストを問題なく更新できます