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

feat: limit the interval for updating quota #288

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions proto/greenfield/storage/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ message Params {
uint64 discontinue_deletion_max = 14;
// The max number for deleting policy in each end block
uint64 stale_policy_cleanup_max = 15;
// The min interval for making quota smaller in seconds
uint64 min_quota_update_interval = 16;
}

// VersionedParams defines the parameters for the storage module with multi version, each version store with different timestamp.
Expand Down
39 changes: 37 additions & 2 deletions x/storage/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,9 @@ func (k Keeper) DeleteBucket(ctx sdk.Context, operator sdk.AccAddress, bucketNam

func (k Keeper) doDeleteBucket(ctx sdk.Context, operator sdk.AccAddress, bucketInfo *types.BucketInfo) error {
store := ctx.KVStore(k.storeKey)
bucketKey := types.GetBucketKey(bucketInfo.BucketName)
store.Delete(bucketKey)
store.Delete(types.GetBucketKey(bucketInfo.BucketName))
store.Delete(types.GetBucketByIDKey(bucketInfo.Id))
store.Delete(types.GetQuotaKey(bucketInfo.Id))

if err := k.appendResourceIdForGarbageCollection(ctx, resource.RESOURCE_TYPE_BUCKET, bucketInfo.Id); err != nil {
return err
Expand Down Expand Up @@ -284,6 +284,21 @@ func (k Keeper) UpdateBucketInfo(ctx sdk.Context, operator sdk.AccAddress, bucke
// handle fields not changed
if opts.ChargedReadQuota == nil {
opts.ChargedReadQuota = &bucketInfo.ChargedReadQuota
} else if *opts.ChargedReadQuota != bucketInfo.ChargedReadQuota {
blockTime := uint64(ctx.BlockTime().Unix())
if *opts.ChargedReadQuota < bucketInfo.ChargedReadQuota {
minInterval := k.GetParams(ctx).MinQuotaUpdateInterval
lastUpdateTime, found := k.getQuotaUpdateTime(ctx, bucketInfo.Id)
if !found {
return types.ErrUpdateQuotaFailed
}
if lastUpdateTime+minInterval > blockTime {
return types.ErrUpdateQuotaFailed.Wrapf("The quota can be updated to a smaller value before %d timestamp",
lastUpdateTime+minInterval)
}
}
// save quota update time
k.setQuotaUpdateTime(ctx, bucketInfo.Id, blockTime)
}

if opts.Visibility != types.VISIBILITY_TYPE_UNSPECIFIED {
Expand Down Expand Up @@ -1649,3 +1664,23 @@ func (k Keeper) garbageCollectionForResource(ctx sdk.Context, deleteStalePolicie
}
return deletedTotal, true
}

func (k Keeper) setQuotaUpdateTime(ctx sdk.Context, bucketId types.Uint, timestamp uint64) {
store := ctx.KVStore(k.storeKey)
bz := make([]byte, 8)
binary.BigEndian.PutUint64(bz, timestamp)
store.Set(types.GetQuotaKey(bucketId), bz)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the quota update time be stored directly in bucketInfo? It didn't feel necessary to add a separate key

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or, I think we should separate some frequently modified fields from bucketInfo as a separate key-value.

Copy link
Contributor Author

@forcodedancing forcodedancing Jun 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the update frequency of quote is very low, or even no update at all.
currently, if there is no update, it will not be stored (just use bucket' creation time).

}

func (k Keeper) getQuotaUpdateTime(ctx sdk.Context, bucketId types.Uint) (uint64, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.GetQuotaKey(bucketId))
if bz != nil {
return binary.BigEndian.Uint64(bz), true
}
bucketInfo, found := k.GetBucketInfoById(ctx, bucketId)
if !found {
return 0, false
}
return uint64(bucketInfo.CreateAt), true
}
1 change: 1 addition & 0 deletions x/storage/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ var (
ErrInvalidApproval = errors.Register(ModuleName, 1116, "Invalid approval of sp")
ErrChargeFailed = errors.Register(ModuleName, 1117, "charge failed error")
ErrInvalidVisibility = errors.Register(ModuleName, 1118, "Invalid type of visibility")
ErrUpdateQuotaFailed = errors.Register(ModuleName, 1119, "Update quota failed")

ErrNoSuchPolicy = errors.Register(ModuleName, 1120, "No such Policy")
ErrInvalidParameter = errors.Register(ModuleName, 1121, "Invalid parameter")
Expand Down
6 changes: 6 additions & 0 deletions x/storage/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ var (
BucketPrefix = []byte{0x11}
ObjectPrefix = []byte{0x12}
GroupPrefix = []byte{0x13}
QuotaPrefix = []byte{0x14}

BucketByIDPrefix = []byte{0x21}
ObjectByIDPrefix = []byte{0x22}
Expand Down Expand Up @@ -133,3 +134,8 @@ func GetDeleteStalePoliciesKey(height int64) []byte {
binary.BigEndian.PutUint64(bz, uint64(height))
return append(DeleteStalePoliciesPrefix, bz...)
}

// GetQuotaKey return the quota store key
func GetQuotaKey(bucketId math.Uint) []byte {
return append(QuotaPrefix, sequence.EncodeSequence(bucketId)...)
}
15 changes: 15 additions & 0 deletions x/storage/types/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const (
DefaultDiscontinueConfirmPeriod int64 = 604800 // 7 days (in second)
DefaultDiscontinueDeletionMax uint64 = 10000
DefaultStalePolicyCleanupMax uint64 = 200
DefaultMinUpdateQuotaInterval uint64 = 2592000 // 30 days (in second)

DefaultMirrorBucketRelayerFee = "250000000000000" // 0.00025
DefaultMirrorBucketAckRelayerFee = "250000000000000" // 0.00025
Expand All @@ -45,6 +46,7 @@ var (
KeyDiscontinueConfirmPeriod = []byte("DiscontinueConfirmPeriod")
KeyDiscontinueDeletionMax = []byte("DiscontinueDeletionMax")
KeyStalePolicyCleanupMax = []byte("StalePolicyCleanupMax")
KeyMinUpdateQuotaInterval = []byte("MinUpdateQuotaInterval")
KeyMirrorBucketRelayerFee = []byte("MirrorBucketRelayerFee")
KeyMirrorBucketAckRelayerFee = []byte("MirrorBucketAckRelayerFee")
KeyMirrorObjectRelayerFee = []byte("MirrorObjectRelayerFee")
Expand All @@ -71,6 +73,7 @@ func NewParams(
discontinueConfirmPeriod int64,
discontinueDeletionMax uint64,
stalePoliesCleanupMax uint64,
minUpdateQuotaInterval uint64,
) Params {
return Params{
VersionedParams: VersionedParams{
Expand All @@ -93,6 +96,7 @@ func NewParams(
DiscontinueConfirmPeriod: discontinueConfirmPeriod,
DiscontinueDeletionMax: discontinueDeletionMax,
StalePolicyCleanupMax: stalePoliesCleanupMax,
MinQuotaUpdateInterval: minUpdateQuotaInterval,
}
}

Expand All @@ -106,6 +110,7 @@ func DefaultParams() Params {
DefaultMirrorGroupRelayerFee, DefaultMirrorGroupAckRelayerFee,
DefaultDiscontinueCountingWindow, DefaultDiscontinueObjectMax, DefaultDiscontinueBucketMax,
DefaultDiscontinueConfirmPeriod, DefaultDiscontinueDeletionMax, DefaultStalePolicyCleanupMax,
DefaultMinUpdateQuotaInterval,
)
}

Expand All @@ -131,6 +136,7 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {
paramtypes.NewParamSetPair(KeyDiscontinueConfirmPeriod, &p.DiscontinueConfirmPeriod, validateDiscontinueConfirmPeriod),
paramtypes.NewParamSetPair(KeyDiscontinueDeletionMax, &p.DiscontinueDeletionMax, validateDiscontinueDeletionMax),
paramtypes.NewParamSetPair(KeyStalePolicyCleanupMax, &p.StalePolicyCleanupMax, validateStalePolicyCleanupMax),
paramtypes.NewParamSetPair(KeyMinUpdateQuotaInterval, &p.MinQuotaUpdateInterval, validateMinUpdateQuotaInterval),
}
}

Expand Down Expand Up @@ -391,3 +397,12 @@ func validateStalePolicyCleanupMax(i interface{}) error {
}
return nil
}

func validateMinUpdateQuotaInterval(i interface{}) error {
_, ok := i.(uint64)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}

return nil
}
125 changes: 82 additions & 43 deletions x/storage/types/params.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.