-
Notifications
You must be signed in to change notification settings - Fork 50
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: Add ACP to pubsub KMS #3206
Changes from 12 commits
0b8bca9
42fec71
a8edea0
ac77afd
711c1af
784217e
b60370d
a475089
5dad4b4
e52c61b
f02c09d
5c03868
1bab128
fd326a2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// Copyright 2024 Democratized Data Foundation | ||
// | ||
// Use of this software is governed by the Business Source License | ||
// included in the file licenses/BSL.txt. | ||
// | ||
// As of the Change Date specified in that file, in accordance with | ||
// the Business Source License, use of this software will be governed | ||
// by the Apache License, Version 2.0, included in the file | ||
// licenses/APL.txt. | ||
|
||
package db | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/sourcenetwork/immutable" | ||
|
||
"github.com/sourcenetwork/defradb/client" | ||
"github.com/sourcenetwork/defradb/internal/db/description" | ||
) | ||
|
||
// collectionRetriever is a helper struct that retrieves a collection from a document ID. | ||
type collectionRetriever struct { | ||
db client.DB | ||
} | ||
|
||
// NewCollectionRetriever creates a new CollectionRetriever. | ||
func NewCollectionRetriever(db client.DB) *collectionRetriever { | ||
return &collectionRetriever{ | ||
db: db, | ||
} | ||
} | ||
|
||
// RetrieveCollectionFromDocID retrieves a collection from a document ID. | ||
func (r *collectionRetriever) RetrieveCollectionFromDocID( | ||
ctx context.Context, | ||
docID string, | ||
) (client.Collection, error) { | ||
ctx, txn, err := ensureContextTxn(ctx, r.db, false) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer txn.Discard(ctx) | ||
|
||
headIterator, err := NewHeadBlocksIteratorFromTxn(ctx, txn, docID) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
hasValue, err := headIterator.Next() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if !hasValue { | ||
return nil, NewErrDocIDNotFound(docID) | ||
} | ||
|
||
schema, err := description.GetSchemaVersion(ctx, txn, headIterator.CurrentBlock().Delta.GetSchemaVersionID()) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
cols, err := r.db.GetCollections( | ||
ctx, | ||
client.CollectionFetchOptions{ | ||
SchemaRoot: immutable.Some(schema.Root), | ||
}, | ||
) | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if len(cols) == 0 { | ||
return nil, NewErrCollectionWithSchemaRootNotFound(schema.Root) | ||
} | ||
|
||
return cols[0], nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
// Copyright 2024 Democratized Data Foundation | ||
// | ||
// Use of this software is governed by the Business Source License | ||
// included in the file licenses/BSL.txt. | ||
// | ||
// As of the Change Date specified in that file, in accordance with | ||
// the Business Source License, use of this software will be governed | ||
// by the Apache License, Version 2.0, included in the file | ||
// licenses/APL.txt. | ||
|
||
package db | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/ipfs/go-cid" | ||
|
||
"github.com/sourcenetwork/defradb/datastore" | ||
"github.com/sourcenetwork/defradb/internal/core" | ||
coreblock "github.com/sourcenetwork/defradb/internal/core/block" | ||
"github.com/sourcenetwork/defradb/internal/keys" | ||
"github.com/sourcenetwork/defradb/internal/merkle/clock" | ||
) | ||
|
||
// DocHeadBlocksIterator is an iterator that iterates over the head blocks of a document. | ||
type DocHeadBlocksIterator struct { | ||
ctx context.Context | ||
blockstore datastore.Blockstore | ||
cids []cid.Cid | ||
|
||
currentCid cid.Cid | ||
currentBlock *coreblock.Block | ||
currentRawBlock []byte | ||
} | ||
|
||
// NewHeadBlocksIterator creates a new DocHeadBlocksIterator. | ||
func NewHeadBlocksIterator( | ||
ctx context.Context, | ||
headstore datastore.DSReaderWriter, | ||
blockstore datastore.Blockstore, | ||
docID string, | ||
) (*DocHeadBlocksIterator, error) { | ||
headStoreKey := keys.HeadStoreKey{ | ||
DocID: docID, | ||
FieldID: core.COMPOSITE_NAMESPACE, | ||
} | ||
headset := clock.NewHeadSet(headstore, headStoreKey) | ||
cids, _, err := headset.List(ctx) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. todo: There appears to be no reason to fully scan all the head cids in the constructor, only to return an iterator from it that then iterates through the results. It seems to defeat the point a little bit and makes the code look odd, and more scary than it needs to be. This is worse given that in the normal/happy use-case (RetrieveCollectionFromDocID, not retry), Please rework this (maybe make Note: Please see my note RE a bug in the model before spending time on this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It uses all produced value in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I missed I'm not sure we'll convince each other either way here though, and it's only immediate impact on users is (probably minor) performance, so if you don't want to do the suggestion please leave this thread unresolved in case anyone else feels like joining the conversation :) |
||
if err != nil { | ||
return nil, err | ||
} | ||
return &DocHeadBlocksIterator{ | ||
ctx: ctx, | ||
blockstore: blockstore, | ||
cids: cids, | ||
}, nil | ||
} | ||
|
||
// NewHeadBlocksIteratorFromTxn creates a new DocHeadBlocksIterator from a transaction. | ||
func NewHeadBlocksIteratorFromTxn( | ||
ctx context.Context, | ||
txn datastore.Txn, | ||
docID string, | ||
) (*DocHeadBlocksIterator, error) { | ||
return NewHeadBlocksIterator(ctx, txn.Headstore(), txn.Blockstore(), docID) | ||
} | ||
|
||
// Next advances the iterator to the next block. | ||
func (h *DocHeadBlocksIterator) Next() (bool, error) { | ||
if len(h.cids) == 0 { | ||
return false, nil | ||
} | ||
nextCid := h.cids[0] | ||
h.cids = h.cids[1:] | ||
|
||
rawBlock, err := h.blockstore.Get(h.ctx, nextCid) | ||
if err != nil { | ||
return false, err | ||
} | ||
blk, err := coreblock.GetFromBytes(rawBlock.RawData()) | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
h.currentCid = nextCid | ||
h.currentBlock = blk | ||
h.currentRawBlock = rawBlock.RawData() | ||
return true, nil | ||
} | ||
|
||
// CurrentCid returns the CID of the current block. | ||
func (h *DocHeadBlocksIterator) CurrentCid() cid.Cid { | ||
return h.currentCid | ||
} | ||
|
||
// CurrentBlock returns the current block. | ||
func (h *DocHeadBlocksIterator) CurrentBlock() *coreblock.Block { | ||
return h.currentBlock | ||
} | ||
|
||
// CurrentRawBlock returns the raw data of the current block. | ||
func (h *DocHeadBlocksIterator) CurrentRawBlock() []byte { | ||
return h.currentRawBlock | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
todo: This function is scoped to a large and important type, does very similar things to a couple of existing places, and ignores the context txn. It looks very easy to erroneously call this, and in an area where testing is relatively weak (transactions).
Please document this function to highlight that it ignores the transaction, and does a whole load of work to find the heads (something the two existing locations do not need to do).
Please do not refactor the existing locations as I have changed them in another open PR, with this 3rd addition we can look at refactoring the 3 after this (and maybe the other PR, depending on timing) has merged.