Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add vstorage write usage metrics #10938

Open
siarhei-agoric opened this issue Feb 4, 2025 · 2 comments
Open

Add vstorage write usage metrics #10938

siarhei-agoric opened this issue Feb 4, 2025 · 2 comments
Assignees
Labels
enhancement New feature or request telemetry

Comments

@siarhei-agoric
Copy link
Contributor

siarhei-agoric commented Feb 4, 2025

What is the Problem Being Solved?

We need to be able to monitor how much is being written into vstorage.

Description of the Design

  1. create necessary APIs using existing cosmos telemetry infrastructure: https://github.com/agoric-labs/cosmos-sdk/blob/Agoric/docs/core/telemetry.md
  2. change Receive() in vstorage.go to capture and feed necessary metrics to cosmos telemetry for set, legacySet, setWithoutNotify, and append
    func (sh vstorageHandler) Receive(cctx context.Context, str string) (ret string, err error) {
    ctx := sdk.UnwrapSDKContext(cctx)
    keeper := sh.keeper
    msg := new(vstorageMessage)
    err = json.Unmarshal([]byte(str), &msg)
    if err != nil {
    return
    }
    // Allow recovery from OutOfGas panics so that we don't crash
    defer func() {
    if r := recover(); r != nil {
    switch rType := r.(type) {
    case sdk.ErrorOutOfGas:
    err = fmt.Errorf(
    "out of gas in location: %v; gasUsed: %d",
    rType.Descriptor, ctx.GasMeter().GasConsumed(),
    )
    default:
    // Not ErrorOutOfGas, so panic again.
    panic(r)
    }
    }
    }()
    // Handle generic paths.
    switch msg.Method {
    case "set":
    for _, arg := range msg.Args {
    var entry agoric.KVEntry
    err = json.Unmarshal(arg, &entry)
    if err != nil {
    return
    }
    keeper.SetStorageAndNotify(ctx, entry)
    }
    return "true", nil
    // We sometimes need to use LegacySetStorageAndNotify, because the solo's
    // chain-cosmos-sdk.js consumes legacy events for `mailbox.*` and `egress.*`.
    // FIXME: Use just "set" and remove this case.
    case "legacySet":
    for _, arg := range msg.Args {
    var entry agoric.KVEntry
    err = json.Unmarshal(arg, &entry)
    if err != nil {
    return
    }
    //fmt.Printf("giving Keeper.SetStorage(%s) %s\n", entry.Path(), entry.Value())
    keeper.LegacySetStorageAndNotify(ctx, entry)
    }
    return "true", nil
    case "setWithoutNotify":
    for _, arg := range msg.Args {
    var entry agoric.KVEntry
    err = json.Unmarshal(arg, &entry)
    if err != nil {
    return
    }
    keeper.SetStorage(ctx, entry)
    }
    return "true", nil
    case "append":
    for _, arg := range msg.Args {
    var entry agoric.KVEntry
    err = json.Unmarshal(arg, &entry)
    if err != nil {
    return
    }
    if !entry.HasValue() {
    err = fmt.Errorf("no value for append entry with path: %q", entry.Key())
    return
    }
    err = keeper.AppendStorageValueAndNotify(ctx, entry.Key(), entry.StringValue())
    if err != nil {
    return
    }
    }
    return "true", nil
    case "get":
    // Note that "get" does not (currently) unwrap a StreamCell.
    var path string
    err = unmarshalSinglePathFromArgs(msg.Args, &path)
    if err != nil {
    return
    }
    entry := keeper.GetEntry(ctx, path)
    bz, err := json.Marshal(entry.Value())
    if err != nil {
    return "", err
    }
    return string(bz), nil
    case "getStoreKey":
    var path string
    err = unmarshalSinglePathFromArgs(msg.Args, &path)
    if err != nil {
    return
    }
    value := vstorageStoreKey{
    StoreName: keeper.GetStoreName(),
    StoreSubkey: string(keeper.PathToEncodedKey(path)),
    DataPrefixBytes: string(keeper.GetDataPrefix()),
    NoDataValue: string(keeper.GetNoDataValue()),
    }
    bz, err := json.Marshal(value)
    if err != nil {
    return "", err
    }
    return string(bz), nil
    case "has":
    var path string
    err = unmarshalSinglePathFromArgs(msg.Args, &path)
    if err != nil {
    return
    }
    value := keeper.HasStorage(ctx, path)
    if !value {
    return "false", nil
    }
    return "true", nil
    // TODO: "keys" is deprecated
    case "children", "keys":
    var path string
    err = unmarshalSinglePathFromArgs(msg.Args, &path)
    if err != nil {
    return
    }
    children := keeper.GetChildren(ctx, path)
    if children.Children == nil {
    return "[]", nil
    }
    bytes, err := json.Marshal(children.Children)
    if err != nil {
    return "", err
    }
    return string(bytes), nil
    case "entries":
    var path string
    err = unmarshalSinglePathFromArgs(msg.Args, &path)
    if err != nil {
    return
    }
    children := keeper.GetChildren(ctx, path)
    entries := make([]agoric.KVEntry, len(children.Children))
    for i, child := range children.Children {
    entry := keeper.GetEntry(ctx, fmt.Sprintf("%s.%s", path, child))
    if !entry.HasValue() {
    entries[i] = agoric.NewKVEntryWithNoValue(child)
    } else {
    entries[i] = agoric.NewKVEntry(child, entry.StringValue())
    }
    }
    bytes, err := json.Marshal(entries)
    if err != nil {
    return "", err
    }
    return string(bytes), nil
    case "values":
    var path string
    err = unmarshalSinglePathFromArgs(msg.Args, &path)
    if err != nil {
    return
    }
    children := keeper.GetChildren(ctx, path)
    vals := make([]*string, len(children.Children))
    for i, child := range children.Children {
    vals[i] = keeper.GetEntry(ctx, fmt.Sprintf("%s.%s", path, child)).Value()
    }
    bytes, err := json.Marshal(vals)
    if err != nil {
    return "", err
    }
    return string(bytes), nil
    case "size":
    var path string
    err = unmarshalSinglePathFromArgs(msg.Args, &path)
    if err != nil {
    return
    }
    children := keeper.GetChildren(ctx, path)
    if children.Children == nil {
    return "0", nil
    }
    return fmt.Sprint(len(children.Children)), nil
    }
    return "", errors.New("Unrecognized msg.Method " + msg.Method)
    }

Security Considerations

TBD

Scaling Considerations

TBD

Test Plan

Manual testing to observe new slog entries for an appropriate pre-existing test case

Upgrade Considerations

TBD

@siarhei-agoric siarhei-agoric added the enhancement New feature or request label Feb 4, 2025
@siarhei-agoric siarhei-agoric self-assigned this Feb 4, 2025
@toliaqat
Copy link
Contributor

toliaqat commented Feb 6, 2025

@siarhei-agoric can you please share what approach you are taking to get vstorage metrics?

@siarhei-agoric
Copy link
Contributor Author

@siarhei-agoric can you please share what approach you are taking to get vstorage metrics?

Yes. Please see updated Description of the Design section in the OP.

@siarhei-agoric siarhei-agoric changed the title Explore, define, and implement vstorage usage metrics Capture vstorage write usage metrics Feb 7, 2025
@siarhei-agoric siarhei-agoric changed the title Capture vstorage write usage metrics Add vstorage write usage metrics Feb 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request telemetry
Projects
None yet
Development

No branches or pull requests

3 participants