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(redis): implement redis caches #1

Merged
merged 15 commits into from
Oct 8, 2024
Merged

Conversation

hannahhoward
Copy link
Member

Goal

Implement the three types of cache interfaces based on the redis cache

Implementation

  • built a general purpose redis cache interface talking to default go redis client library
  • built three special cases to handle serialization/deserialization for ipni cache, the sharded dag index cache, and the content claims cache
  • also fixed a few issues with assert & metadata cause the tests finally exercised them a bit
  • added a bunch of test infra (a lot copied over from go-ucanto)

Copy link
Member

@alanshaw alanshaw left a comment

Choose a reason for hiding this comment

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

🚀 this looks pretty good to me! Just some minor feedback - mostly questions :)

type digest struct {
Digest mh.Multihash
}
type digest mh.Multihash

func (d digest) hasMultihash() {}
Copy link
Member

Choose a reason for hiding this comment

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

What is this for?

Copy link
Member Author

Choose a reason for hiding this comment

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

ha yea actually was just messing around but it's simpler.

}

// RequireEqualIndex compares two sharded dag indexes to verify their equality
func RequireEqualIndex(t *testing.T, expectedIndex blobindex.ShardedDagIndexView, actualIndex blobindex.ShardedDagIndexView) {
Copy link
Member

Choose a reason for hiding this comment

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

Would it be better to blobindex.Archive(...) these and compare the bytes? If we ever add properties to these objects this function could return a false positive...

That said, this is more useful info when they're not equal.

Copy link
Member Author

Choose a reason for hiding this comment

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

yea this is actually used to check a archive/unarchive operation so it seems redundant at this point.

}

// RequireEqualDelegation compares two delegations to verify their equality
func RequireEqualDelegation(t *testing.T, expectedDelegation delegation.Delegation, actualDelegation delegation.Delegation) {
Copy link
Member

Choose a reason for hiding this comment

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

Would it be better to delegation.Archive(...) these and compare the bytes? See previous comment for reasoning.

Copy link
Member Author

Choose a reason for hiding this comment

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

yea again, I'm testing archive/unarchive so this seems better signal

@@ -0,0 +1,5 @@
type ContentClaimMetadata struct {
ClaimType Int
ShortCut Bytes
Copy link
Member

Choose a reason for hiding this comment

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

🙏 can this be named better? Something like "embedded data"/"cached data"/"claimed data"?

Copy link
Member Author

Choose a reason for hiding this comment

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

fair

return delegation.Extract([]byte(data))
}

func delegationToRedis(d delegation.Delegation) (string, error) {
Copy link
Member

Choose a reason for hiding this comment

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

You can store bytes in redis no?

Copy link
Member Author

Choose a reason for hiding this comment

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

yes, but everything is a string to anyway.

Comment on lines 1 to 2
type PeerID bytes
type Multiaddr bytes
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
type PeerID bytes
type Multiaddr bytes
type PeerID Bytes
type Multiaddr Bytes

Copy link
Member Author

Choose a reason for hiding this comment

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

that actually didn't work. I think when you define alias types you have to use the lower case.

}

// Set saves a serialized value to redis
func (rs *Store[Key, Value]) Set(ctx context.Context, key Key, value Value, expires bool) error {
Copy link
Member

Choose a reason for hiding this comment

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

What's the reason to use a boolean vs a duration for expiration?

Copy link
Member Author

@hannahhoward hannahhoward Sep 27, 2024

Choose a reason for hiding this comment

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

I dunno simplicity given it's an abstract interface. also the key distinction I'm thinking of is keys you can remove to keep the cache size down vs keys you dont want to do that on.

}

// SetExpirable changes the expiration property for a given key
func (rs *Store[Key, Value]) SetExpirable(ctx context.Context, key Key, expires bool) error {
Copy link
Member

Choose a reason for hiding this comment

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

When do we want something that previously had no expiry to have one (and vice versa)?

Copy link
Member Author

Choose a reason for hiding this comment

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

it's actually the other way around -- I cached on write before IPNI, so I set NO expiry. Now i want to set YES expiry cause I've confirmed it's actually on IPNI now.

expires time.Duration
}

type MockRedis struct {
Copy link
Member

Choose a reason for hiding this comment

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

There's a mock redis implementation here https://github.com/go-redis/redismock - is this not suitable?

Copy link
Member Author

Choose a reason for hiding this comment

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

yea, I saw this -- generally, I want something a bit more stateful, that's simple and which I understand. I often that particular style of mocking library (seems analogous to this https://github.com/uber-go/mock) quite frustrating and awkward to use, and ultimately it doesn't tell you much. By and large, I just write my own mocks in go, cause I want to understand exactly the behavior that's happening under the hood and to see what comes out of that.

Copy link
Member Author

@hannahhoward hannahhoward Sep 27, 2024

Choose a reason for hiding this comment

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

there's also this -- https://github.com/alicebob/miniredis -- basically the far other end running an in process redis

ultimately I looked at both and was like "it would be easiest for me to write tests against something I expected to behave a very specific way.

@hannahhoward
Copy link
Member Author

@alanshaw can you clarify what your blocking changes requested are? I've responded on several of thees but I'm not sure whether it makes sense to change.

also updates metadata design
implements a parallel walk
implements ProviderIndex
also adds various fixes, tweeks, and rearchitects to prepare for testing
@hannahhoward hannahhoward merged commit c72a14a into main Oct 8, 2024
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.

2 participants