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!: return allocated bytes in store/add receipt #1213

Merged
merged 10 commits into from
Dec 7, 2023

Conversation

alanshaw
Copy link
Member

@alanshaw alanshaw commented Dec 4, 2023

This PR adds a new field to the store/add success result: allocated: number - the total bytes allocated in the space to accommodate the stored item, it may be zero if the item is already stored in this space.

This allows us to accurately report and bill for items stored in a space. Currently, store/add when the item is already stored in the space will cause a new diff to be created, effecitvely counting the same shard multiple times. This could happen because of accidentally uploading the same item, or because of a retry of a big item where some shards were successful.

The following additional changes enable this functionality:

  • StoreTable and UploadTable methods now have return types that are Result<O, X> - this allows us to specify and communicate 2 errors RecordNotFound and RecordKeyConflict (explained in the following bullets).
  • In the context of these 2 tables the semantics of insert have changed to be more in line with postgres/other DBs - "insert" means add to the DB or fail (with RecordKeyConflict) if an item with the same key already exists.
  • In the UploadTable I've renamed insert to upsert since the behaviour in use here is more akin to "update or insert" - aka "upsert".
  • remove and get now fail with RecordNotFound if the item to delete is not available.
    • Again in dynamodb we can satisfy this constraint with condition expressions or ReturnValues

@alanshaw alanshaw changed the title feat: return allocated bytes in store/add receipt feat: return allocated bytes in store/add receipt Dec 4, 2023
Copy link
Contributor

@vasco-santos vasco-santos left a comment

Choose a reason for hiding this comment

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

LGTM
small things inline

packages/upload-api/test/handlers/store.js Show resolved Hide resolved
packages/upload-api/test/handlers/store.js Show resolved Hide resolved
Co-authored-by: Vasco Santos <santos.vasco10@gmail.com>
* Total bytes allocated in the space to accommodate this stored item.
* May be zero if the item is _already_ stored in _this_ space.
*/
allocated: number
Copy link
Contributor

@gobengo gobengo Dec 4, 2023

Choose a reason for hiding this comment

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

We may want to advertise how much we can ensure consistency of this, which I imagine might be 'not very much' unless we have transactions in our underlying db

e.g. let's say cid A is not stored in the space. Two store/add invocations get created with different invocations CIDs (e.g. different nonce/expirty) to add cid A to the space. Then those two invocations are submitted to us at the exact same second. iiuc it may be the case that both of those responses come back with allocated: size(A) (because we dont have transactions, and in this scenario both invocations calls carStoreBucket.has(link) here would have returned false.

my main concern

  • someone might use this allocated response value in some business logic without being aware of the eventual consistency lack-of-transactionality in generating this value. i.e. this could be nonzero even if technically the a different store/add invocation added the CID first (in the race condition describes above).
  • in that race condition, the same CID may have multiple store/add receipts whose results have allocated set to the size of the referent of the CID.

If we want to return this information in the result of the write operation (store/add), we probably need something like transactions to do it in a way that isn't subject to these race conditions.
But if possible it may be nice to avoid returning this value in the result of the write operation (because it almost always increases the cost of the write operation to add return values that. must also be consistent)

alternatively we ignore the above concerns but maybe it's a good idea to at least put in the jsdoc here that there a nonzero response does not necessarily indicate that the store/add is the authoritative addition of the CID to the space.

Copy link
Member Author

Choose a reason for hiding this comment

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

Great point, in hindsight this is maybe not the right solution because we want to use it in our business logic...

Copy link
Contributor

Choose a reason for hiding this comment

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

good point, so maybe we want the insert later on to have a result of being conflict or not. Only one Put should happen in dynamo successfully

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok, on reflection I think we can make allocated in the response be authoratitive about the addition of the CID to the space. This is what we can do:

  • We don't need TransactWriteItems since we're not writing multiple items!
  • We can use conditional expressions to ensure writes fail:
    • Change store/add PutItem so that it fails if not a new record
    • Change store/remove DeleteItem so that it fails if record does not exist

@alanshaw alanshaw changed the title feat: return allocated bytes in store/add receipt feat!: return allocated bytes in store/add receipt Dec 6, 2023
@alanshaw
Copy link
Member Author

alanshaw commented Dec 6, 2023

@gobengo please for another review 🙏

A few changes since you last looked:

  • StoreTable and UploadTable methods now have return types that are Result<O, X> - this allows us to specify and communicate 2 errors RecordNotFound and RecordKeyConflict (explained in the following bullets).
  • In the context of these 2 tables the semantics of insert have changed to be more in line with postgres/other DBs - "insert" means add to the DB or fail (with RecordKeyConflict) if an item with the same key already exists.
  • In the UploadTable I've renamed insert to upsert since the behaviour in use here is more akin to "insert or update" - aka "upsert".
  • remove and get now fail with RecordNotFound if the item to delete is not available.
    • Again in dynamodb we can satisfy this constraint with condition expressions or ReturnValues

Copy link
Contributor

@vasco-santos vasco-santos left a comment

Choose a reason for hiding this comment

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

I think there is some weirdness on the return types of errors? I don't understand why ts is not complaining

@@ -33,7 +33,6 @@ export function storeAddProvider(context) {
},
context
),
storeTable.exists(space, link),
Copy link
Contributor

Choose a reason for hiding this comment

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

nice, we drop a request :)

packages/upload-api/src/store/get.js Show resolved Hide resolved
packages/upload-api/src/store/remove.js Outdated Show resolved Hide resolved
packages/upload-api/src/upload/get.js Show resolved Hide resolved
packages/upload-api/src/upload/remove.js Outdated Show resolved Hide resolved
@alanshaw alanshaw merged commit 5d52e44 into main Dec 7, 2023
14 checks passed
@alanshaw alanshaw deleted the feat/store-add-allocated-bytes branch December 7, 2023 14:35
alanshaw pushed a commit that referenced this pull request Dec 7, 2023
🤖 I have created a release *beep* *boop*
---


##
[13.0.0](capabilities-v12.1.0...capabilities-v13.0.0)
(2023-12-07)


### ⚠ BREAKING CHANGES

* return allocated bytes in `store/add` receipt
([#1213](#1213))

### Features

* return allocated bytes in `store/add` receipt
([#1213](#1213))
([5d52e44](5d52e44))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
alanshaw pushed a commit that referenced this pull request Dec 7, 2023
🤖 I have created a release *beep* *boop*
---


##
[8.0.0](upload-api-v7.3.5...upload-api-v8.0.0)
(2023-12-07)


### ⚠ BREAKING CHANGES

* return allocated bytes in `store/add` receipt
([#1213](#1213))

### Features

* return allocated bytes in `store/add` receipt
([#1213](#1213))
([5d52e44](5d52e44))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: Alan Shaw <alan.shaw@protocol.ai>
alanshaw pushed a commit to storacha/w3infra that referenced this pull request Dec 12, 2023
Uses `allocated` property in the `store/add` receipt to count bytes
added to the space. The `allocated` property will be 0 when the user
tries to add a shard that is already present in the space.

❓ should we store a diff anyway? even though the size did not change?

refs storacha/w3up#1213
travis added a commit that referenced this pull request Jan 3, 2024
🤖 I have created a release *beep* *boop*
---


##
[13.0.0](upload-client-v12.3.2...upload-client-v13.0.0)
(2023-12-14)


### ⚠ BREAKING CHANGES

* return allocated bytes in `store/add` receipt
([#1213](#1213))

### Features

* dont use ipfs-utils fetch with upload progress by default
([#1240](#1240))
([86aedbc](86aedbc))
* return allocated bytes in `store/add` receipt
([#1213](#1213))
([5d52e44](5d52e44))


### Fixes

* bind globalThis.fetch to globalThis
([#1242](#1242))
([ef59358](ef59358))
* point `main` at files included in the package
([#1241](#1241))
([c0b306d](c0b306d))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: Travis Vachon <travis.vachon@protocol.ai>
travis pushed a commit that referenced this pull request Jan 3, 2024
🤖 I have created a release *beep* *boop*
---


##
[12.0.0](w3up-client-v11.2.1...w3up-client-v12.0.0)
(2024-01-03)


### ⚠ BREAKING CHANGES

* return allocated bytes in `store/add` receipt
([#1213](#1213))

### Features

* expose OwnedSpace and SharedSpace from access-client
([#1244](#1244))
([8ec1b44](8ec1b44))
* return allocated bytes in `store/add` receipt
([#1213](#1213))
([5d52e44](5d52e44))


### Fixes

* copy src into dist in w3up-client
([#1239](#1239))
([468bb79](468bb79))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
Copy link

@ALIK202 ALIK202 left a comment

Choose a reason for hiding this comment

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

0xBa5c04Cdf4771ac6Da3f48fc368314a00DA064B7

vasco-santos added a commit that referenced this pull request Jan 15, 2024
🤖 I have created a release *beep* *boop*
---


##
[4.3.1](filecoin-api-v4.3.0...filecoin-api-v4.3.1)
(2024-01-15)


### ⚠ BREAKING CHANGES

* return allocated bytes in `store/add` receipt
([#1213](#1213))

### Features

* return allocated bytes in `store/add` receipt
([#1213](#1213))
([5d52e44](5d52e44))
* upload-client uploadDirectory, by default, sorts the provided files by
file name to help the user call us in a way that is deterministic and
minimizes cost
([#1173](#1173))
([8cd2555](8cd2555))


### Fixes

* avoid duplicates on aggregator buffer concat
([#1259](#1259))
([9e64bab](9e64bab))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: Vasco Santos <santos.vasco10@gmail.com>
alanshaw pushed a commit to storacha/upload-service that referenced this pull request Nov 5, 2024
🤖 I have created a release *beep* *boop*
---


## 1.0.0 (2024-11-05)


### ⚠ BREAKING CHANGES

* add `index/add` handler
([storacha#1421](https://github.com/storacha/upload-service/issues/1421))
* restrict store API to CARs
([storacha#1415](https://github.com/storacha/upload-service/issues/1415))
* **capabilities:** `BlobMultihash` type in `@web3-storage/capabilities`
renamed to `Multihash`.
* allocations storage interface now requires remove to be implemented
* return allocated bytes in `store/add` receipt
([storacha#1213](https://github.com/storacha/upload-service/issues/1213))
* coupon
([storacha#1136](https://github.com/storacha/upload-service/issues/1136))
* see latest specs
https://github.com/web3-storage/specs/blob/cbdb706f18567900c5c24d7fb16ccbaf93d0d023/w3-filecoin.md
* filecoin client to use new capabilities
* filecoin capabilities

### refactor

* filecoin api services events and tests
([storacha#974](https://github.com/storacha/upload-service/issues/974))
([953537b](953537b))
* filecoin capabilities
([c0b97bf](c0b97bf))
* filecoin client to use new capabilities
([b0d9c3f](b0d9c3f))


### Features

* add "plan/create-admin-session" capability
([storacha#1411](https://github.com/storacha/upload-service/issues/1411))
([50eeeb5](50eeeb5))
* add `index/add` handler
([storacha#1421](https://github.com/storacha/upload-service/issues/1421))
([cbe9524](cbe9524))
* add `initialize` method to `PlansStorage`
([storacha#1278](https://github.com/storacha/upload-service/issues/1278))
([6792126](6792126))
* add `store/get` and `upload/get` capabilities
([storacha#942](https://github.com/storacha/upload-service/issues/942))
([40c79eb](40c79eb))
* add `subscription/list` capability
([storacha#1088](https://github.com/storacha/upload-service/issues/1088))
([471d7e5](471d7e5))
* add a function to verify and return Abilities.
([storacha#1252](https://github.com/storacha/upload-service/issues/1252))
([2f026a2](2f026a2))
* add blob list and remove
([storacha#1385](https://github.com/storacha/upload-service/issues/1385))
([2f69946](2f69946))
* add blob protocol to upload-client
([storacha#1425](https://github.com/storacha/upload-service/issues/1425))
([49aef56](49aef56))
* add blob/get
([storacha#1484](https://github.com/storacha/upload-service/issues/1484))
([328039d](328039d))
* add revocation to access-client and w3up-client
([storacha#975](https://github.com/storacha/upload-service/issues/975))
([6c877aa](6c877aa))
* add usage/report capability
([storacha#1079](https://github.com/storacha/upload-service/issues/1079))
([6418b4b](6418b4b))
* blob, web3.storage and ucan conclude capabilities together with api
handlers
([storacha#1342](https://github.com/storacha/upload-service/issues/1342))
([00735a8](00735a8))
* **capabilities:** add `index/add` capability
([storacha#1410](https://github.com/storacha/upload-service/issues/1410))
([1b71b89](1b71b89))
* change `plan/update` to `plan/set` and use existing `PlansStorage#set`
to implement an invocation handler
([storacha#1258](https://github.com/storacha/upload-service/issues/1258))
([1ccbfe9](1ccbfe9))
* coupon
([storacha#1136](https://github.com/storacha/upload-service/issues/1136))
([1b94f2d](1b94f2d))
* filecoin info
([storacha#1091](https://github.com/storacha/upload-service/issues/1091))
([adb2442](adb2442))
* Generate Space proofs on the fly, on `access/claim`
([storacha#1555](https://github.com/storacha/upload-service/issues/1555))
([9e2b1d4](9e2b1d4))
* implement `plan/get` capability
([storacha#1005](https://github.com/storacha/upload-service/issues/1005))
([f0456d2](f0456d2))
* introduce capability for changing billing plan
([storacha#1253](https://github.com/storacha/upload-service/issues/1253))
([d33b3a9](d33b3a9))
* move aggregate information out of deals in filecoin/info
([storacha#1192](https://github.com/storacha/upload-service/issues/1192))
([18dc590](18dc590))
* publish index claim
([storacha#1487](https://github.com/storacha/upload-service/issues/1487))
([237b0c6](237b0c6))
* restrict store API to CARs
([storacha#1415](https://github.com/storacha/upload-service/issues/1415))
([e53aa87](e53aa87))
* return allocated bytes in `store/add` receipt
([storacha#1213](https://github.com/storacha/upload-service/issues/1213))
([5d52e44](5d52e44))
* router ([#11](#11))
([c810735](c810735))
* upgrade ucanto/transport to 9.1.0 in all packages to get more verbose
errors from HTTP transport on non-ok response
([storacha#1312](https://github.com/storacha/upload-service/issues/1312))
([d6978d7](d6978d7))
* usage/record capability definition
([storacha#1562](https://github.com/storacha/upload-service/issues/1562))
([98c8a87](98c8a87))
* wip router
([ffcd9c7](ffcd9c7))


### Fixes

* add missing ContentNotFound definition for filecoin offer failure
([c0b97bf](c0b97bf))
* add missing filecoin submit success and failure types
([c0b97bf](c0b97bf))
* capabilities should export blob caps
([storacha#1376](https://github.com/storacha/upload-service/issues/1376))
([460729e](460729e))
* client tests
([b0d9c3f](b0d9c3f))
* fix arethetypesworking errors in all packages
([storacha#1004](https://github.com/storacha/upload-service/issues/1004))
([2e2936a](2e2936a))
* issue where typedoc docs would only show full docs for w3up-client
([storacha#1141](https://github.com/storacha/upload-service/issues/1141))
([0b8d3f3](0b8d3f3))
* migrate repo
([storacha#1389](https://github.com/storacha/upload-service/issues/1389))
([475a287](475a287))
* one more tweak to the `PlanStorage` interface
([storacha#1280](https://github.com/storacha/upload-service/issues/1280))
([5a44565](5a44565))
* package metadata
([storacha#1161](https://github.com/storacha/upload-service/issues/1161))
([b8a1cc2](b8a1cc2))
* put access.session back
([storacha#1100](https://github.com/storacha/upload-service/issues/1100))
([10a1a4b](10a1a4b))
* rename blob and index client capabilities
([storacha#1478](https://github.com/storacha/upload-service/issues/1478))
([17e3a31](17e3a31))
* repo URLs
([storacha#1550](https://github.com/storacha/upload-service/issues/1550))
([e02ddf3](e02ddf3))
* tests
([b179910](b179910))
* trigger capabilities release
([storacha#1399](https://github.com/storacha/upload-service/issues/1399))
([7d9ab35](7d9ab35))
* type errors
([c0b97bf](c0b97bf))
* update data-segment dep
([228ff79](228ff79))
* upgrade @ucanto/validator with bugfix
([storacha#1151](https://github.com/storacha/upload-service/issues/1151))
([d4e961b](d4e961b))
* upgrade ucanto core
([storacha#1127](https://github.com/storacha/upload-service/issues/1127))
([5ce4d22](5ce4d22))
* upgrade ucanto in filecoin api
([c95fb54](c95fb54))
* upgrade ucanto libs and format filecoin api
([storacha#1359](https://github.com/storacha/upload-service/issues/1359))
([87ca098](87ca098))
* upload API test fixes
([6b0d72d](6b0d72d))


### Other Changes

* Add `pnpm dev` to watch-build all packages
([storacha#1533](https://github.com/storacha/upload-service/issues/1533))
([07970ef](07970ef))
* **main:** release capabilities 10.1.0
([storacha#979](https://github.com/storacha/upload-service/issues/979))
([bdd3970](bdd3970))
* **main:** release capabilities 10.2.0
([storacha#983](https://github.com/storacha/upload-service/issues/983))
([a906488](a906488))
* **main:** release capabilities 11.0.0
([storacha#994](https://github.com/storacha/upload-service/issues/994))
([76b0489](76b0489))
* **main:** release capabilities 11.0.1
([storacha#1008](https://github.com/storacha/upload-service/issues/1008))
([37cdc5a](37cdc5a))
* **main:** release capabilities 11.1.0
([storacha#1026](https://github.com/storacha/upload-service/issues/1026))
([7fdb541](7fdb541))
* **main:** release capabilities 11.2.0
([storacha#1084](https://github.com/storacha/upload-service/issues/1084))
([0e7b6dc](0e7b6dc))
* **main:** release capabilities 11.3.0
([storacha#1098](https://github.com/storacha/upload-service/issues/1098))
([7d671bd](7d671bd))
* **main:** release capabilities 11.3.1
([storacha#1101](https://github.com/storacha/upload-service/issues/1101))
([20b5b35](20b5b35))
* **main:** release capabilities 11.4.0
([storacha#1105](https://github.com/storacha/upload-service/issues/1105))
([1b6210f](1b6210f))
* **main:** release capabilities 11.4.1
([storacha#1131](https://github.com/storacha/upload-service/issues/1131))
([a5b7154](a5b7154))
* **main:** release capabilities 12.0.0
([storacha#1137](https://github.com/storacha/upload-service/issues/1137))
([bb23e9f](bb23e9f))
* **main:** release capabilities 12.0.1
([storacha#1147](https://github.com/storacha/upload-service/issues/1147))
([d1a9c78](d1a9c78))
* **main:** release capabilities 12.0.2
([storacha#1152](https://github.com/storacha/upload-service/issues/1152))
([b9d7ff5](b9d7ff5))
* **main:** release capabilities 12.0.3
([storacha#1163](https://github.com/storacha/upload-service/issues/1163))
([ec5c385](ec5c385))
* **main:** release capabilities 12.1.0
([storacha#1195](https://github.com/storacha/upload-service/issues/1195))
([a21c1a5](a21c1a5))
* **main:** release capabilities 13.0.0
([storacha#1230](https://github.com/storacha/upload-service/issues/1230))
([3d5b3ef](3d5b3ef))
* **main:** release capabilities 13.1.0
([storacha#1257](https://github.com/storacha/upload-service/issues/1257))
([85adc9a](85adc9a))
* **main:** release capabilities 13.1.1
([storacha#1283](https://github.com/storacha/upload-service/issues/1283))
([31c38e9](31c38e9))
* **main:** release capabilities 13.2.0
([storacha#1315](https://github.com/storacha/upload-service/issues/1315))
([0505458](0505458))
* **main:** release capabilities 13.2.1
([storacha#1362](https://github.com/storacha/upload-service/issues/1362))
([26b5751](26b5751))
* **main:** release capabilities 13.3.0
([storacha#1366](https://github.com/storacha/upload-service/issues/1366))
([d6fbc4a](d6fbc4a))
* **main:** release capabilities 13.3.1
([storacha#1377](https://github.com/storacha/upload-service/issues/1377))
([149f592](149f592))
* **main:** release capabilities 14.0.0
([storacha#1386](https://github.com/storacha/upload-service/issues/1386))
([69bfc08](69bfc08))
* **main:** release capabilities 14.0.1
([storacha#1395](https://github.com/storacha/upload-service/issues/1395))
([a76c970](a76c970))
* **main:** release capabilities 14.0.2
([storacha#1400](https://github.com/storacha/upload-service/issues/1400))
([7b46852](7b46852))
* **main:** release capabilities 15.0.0
([storacha#1412](https://github.com/storacha/upload-service/issues/1412))
([ec90b81](ec90b81))
* **main:** release capabilities 16.0.0
([storacha#1419](https://github.com/storacha/upload-service/issues/1419))
([50e3934](50e3934))
* **main:** release capabilities 17.0.0
([storacha#1428](https://github.com/storacha/upload-service/issues/1428))
([6ee21fd](6ee21fd))
* **main:** release capabilities 17.1.0
([storacha#1447](https://github.com/storacha/upload-service/issues/1447))
([8ee1fd9](8ee1fd9))
* **main:** release capabilities 17.1.1
([storacha#1483](https://github.com/storacha/upload-service/issues/1483))
([5394ed5](5394ed5))
* **main:** release capabilities 17.2.0
([storacha#1494](https://github.com/storacha/upload-service/issues/1494))
([99876a5](99876a5))
* **main:** release capabilities 17.3.0
([storacha#1503](https://github.com/storacha/upload-service/issues/1503))
([891c2a5](891c2a5))
* **main:** release capabilities 17.4.0
([storacha#1559](https://github.com/storacha/upload-service/issues/1559))
([feaea7a](feaea7a))
* no longer depends on hd-scripts, packages use/configure eslint
directly, fixes warnings from npm lint script
([storacha#1058](https://github.com/storacha/upload-service/issues/1058))
([ebdb99b](ebdb99b))
* package renames
([0f797ed](0f797ed))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants