ScalarDL のファンクションの書き方に関するガイド
このページは英語版のページが機械翻訳されたものです。英語版との間に矛盾または不一致がある場合は、英語版を正としてください。
このドキュメントでは、ScalarDL のファンクションを作成するためのガイドラインをいくつか示します。
ScalarDL のファンクションとは何ですか?
ScalarDL のファンクション(スマートファンクション)は、単一のビジネ スロジックを実装するために記述された JacksonBasedFunction クラスのような定義済みのベースファンクションを拡張する Java プログラムです。単一のビジネス ロジックを実装するために作成されます。 Function は主に ScalarDL アプリケーションのデータを管理し、Contract はデータの証拠を管理します。 これを見る前に、ScalarDL 入門 と ScalarDL のコントラクトの書き方 を参照して、ScalarDL とは何か、ScalarDL とコントラクトで何ができるかを理解してください。
背景
ScalarDL のコントラクトによって管理されるアセットは改ざん防止機能があり、追加のみが可能なため、さまざまなアプリケーションをモデル化する際にそのデータ構造が制限されます。 さらに、改ざん証拠を保証するためにアセットを削除することはできません。 多くの分散 Ledger プラットフォームは、Ledger の前に RDBMS などの別のデータベースを配置して、データベース内のアプリケーションのデータを処理し、証拠として Ledger にログを書き込むことでこの問題に対処しています。 ただし、データベースと Ledger の間のデータの一貫性が常に維持されるとは限らないため、このスキームは理想的ではありません。 致命的な障害により、アプリケーションの Ledger に対応するログが存在しない場合があり、証拠として Ledger にログを書き込む目的が無効になります。 ScalarDL は、アプリケーションのデータを管理するファンクションを導入し、ScalarDB で基盤となる分散 ACID トランザクションを利用してコントラクトとファンクションをアトミックに実行することで、別のアプローチで問題を解決します。
ファンクションを書く
ファンクションの書き方をよりよく理解するために、 Payment
ファンクションを詳しく見てみましょう。
public class Payment extends JacksonBasedFunction {
private final String FROM_KEY_NAME = "from";
private final String TO_KEY_NAME = "to";
private final String AMOUNT_KEY_NAME = "amount";
private final String NAMESPACE_KEY_NAME = "namespace";
private final String TABLE_KEY_NAME = "table";
@Nullable
@Override
public JsonNode invoke(
Database<Get, Scan, Put, Delete, Result> database,
@Nullable JsonNode functionArgument,
JsonNode contractArgument,
@Nullable JsonNode contractProperties) {
// error handling is omitted
String fromId = contractArgument.get(FROM_KEY_NAME).asText();
String toId = contractArgument.get(TO_KEY_NAME).asText();
int amount = contractArgument.get(AMOUNT_KEY_NAME).asInt();
String namespace = contractProperties.get(NAMESPACE_KEY_NAME).asText();
String table = contractProperties.get(TABLE_KEY_NAME).asText();
Key fromKey = Key.ofText("id", fromId);
Key toKey = Key.ofText("id", toId);
// get the account balances
Optional<Result> account1 =
database.get(
Get.newBuilder().namespace(namespace).table(table).partitionKey(fromKey).build());
Optional<Result> account2 =
database.get(
Get.newBuilder().namespace(namespace).table(table).partitionKey(toKey).build());
// assumes that both accounts exist, but it should be checked in production code
long balance1 = account1.get().getInt("balance");
long balance2 = account2.get().getInt("balance");
if (balance1 - amount < 0) {
throw new ContractContextException(
"The account " + fromId + " does not have enough account balance.");
}
// transfer amount
balance1 -= amount;
balance2 += amount;
// update the account balances
database.put(
Put.newBuilder()
.namespace(namespace)
.table(table)
.partitionKey(fromKey)
.bigIntValue("balance", balance1)
.build());
database.put(
Put.newBuilder()
.namespace(namespace)
.table(table)
.partitionKey(toKey)
.bigIntValue("balance", balance2)
.build());
return null;
}
}
これは、ScalarDB API で記述された送金アプリケーションであり、指定された口座残高を取得し、2 つの口座残高間で指定された金額を送金し、残高を更新します。 ScalarDB API の詳細については、ScalarDB ドキュメント もお読みください。
基本ファンクション
事前定義された基本コントラクトと同様に、ScalarDL は事前定義された基本ファンクションも提供します。 たとえば、上記の PaymentFunction は、JacksonBasedFunction と呼ばれる基本ファンクションの 1 つに基づいており、これにより、Jackson の JsonNode 形式でファンクションの入出力を処理できるようになります。
これを書いている時点では、以下に示す 4 つの基本ファンクションが提供されています。 ただし、開発の生産性とパフォーマンスのバランスを適切に保つには、JacksonBasedFunction を使用することをお勧めします。
基本ファンクションクラス | ファンクションの入力と出力のタイプ | ライブラリ |
---|---|---|
JacksonBasedFunction (おすすめ) | JsonNode | Jackson |
JsonpBasedFunction | JsonObject | JSONP |
StringBasedFunction | String | Java標準ライブラリ |
Function (廃止された) | JsonObject | JSONP |
The old Function is still available, but it is now deprecated and will be removed in a later major version. So, it is highly recommended to use the above new (non-deprecated) Functions as a base Function.
古い ファンクション はまだ利用可能ですが、現在は非推奨となっており、 後のメジャー バージョンでは削除されました。 したがって、上記の新しい (非推奨ではない) ファンクションを基本ファンクションとして使用することを強くお勧めします。