Skip to content
This repository has been archived by the owner on Feb 15, 2023. It is now read-only.

serialize dependencies into protobuf #165

Merged
merged 7 commits into from
Sep 20, 2018
Merged

Conversation

changpingc
Copy link
Contributor

We'd like to ship dependencies out of thunder server process, which allows us to restore a subscription and avoid expensive initial computation when a client reconnects and resumes prior subscriptions. This also enables external dependency invalidator that can make thunder server stateless.

@changpingc changpingc changed the title serialize dependencies serialize dependencies into protobuf Sep 12, 2018
@coveralls
Copy link

coveralls commented Sep 12, 2018

Pull Request Test Coverage Report for Build 1064

  • 84 of 152 (55.26%) changed or added relevant lines in 4 files are covered.
  • 4 unchanged lines in 1 file lost coverage.
  • Overall coverage increased (+0.9%) to 65.5%

Changes Missing Coverage Covered Lines Changed/Added Lines %
reactive/util.go 0 1 0.0%
livesql/live.go 6 21 28.57%
reactive/rerunner.go 4 24 16.67%
livesql/marshal.go 74 106 69.81%
Files with Coverage Reduction New Missed Lines %
graphql/schemabuilder/reflect.go 4 71.56%
Totals Coverage Status
Change from base Build 1055: 0.9%
Covered Lines: 3444
Relevant Lines: 5258

💛 - Coveralls

@berfarah
Copy link
Contributor

@changpingc Do you mind putting the reverts in a separate PR? 😬

@changpingc
Copy link
Contributor Author

revert landed separately in #167.

}

type Serializable interface {
proto.Message
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we make this a loose coupling by supporting an interface rather than importing proto? I'm open to being overruled here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure it can turn this into Marshal(), Unmarshal() probably

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

case float64:
return float64(v)
case time.Time:
return time.Time(v)
Copy link
Contributor

Choose a reason for hiding this comment

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

There are some types here that we're doing nothing with. Do we need to handle them?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this handles all driver.Value.

Copy link
Contributor

Choose a reason for hiding this comment

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

This handles more than driver.Value - for example, uint32 is not a driver.Value, only int64 is

Copy link
Contributor Author

Choose a reason for hiding this comment

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

opened a separate PR #170

)

func valueToField(value interface{}) (*thunderpb.Field, error) {
switch column := sqlgen.MakeCanonical(value).(type) {
Copy link
Contributor

Choose a reason for hiding this comment

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

What happens for custom types?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Talked offline. We are going to support it by storing driver.Value. See last commit!

@changpingc changpingc force-pushed the changping/serialize branch 7 times, most recently from 810bd16 to 315c964 Compare September 14, 2018 21:16

type Serializable interface {
// proto.Marshaler and proto.Unmarshaler.
Marshal() ([]byte, error)
Copy link
Contributor

Choose a reason for hiding this comment

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

Could use UnmarshalBinary/MarshalBinary and wrap our resource, but I'm cool with this / exposing this interface

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't particularly like that.. Feels too clunky to wrap.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah but would also be a built-in interface. I'm ok with not wrapping.


if serializable != nil {
depSet, ok := ctx.Value(dependencySetKey{}).(*dependencySet)
if ok && depSet != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: seems nice to have getter/setter methods on the dependency set rather than handling it here and below

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

reactive/util.go Outdated
)

func InvalidateAfter(ctx context.Context, d time.Duration) {
r := NewResource()
timer := time.AfterFunc(d, r.Invalidate)
r.Cleanup(func() { timer.Stop() })
AddDependency(ctx, r, nil)
AddDependency(ctx, r, &thunderpb.ExpirationTime{Time: time.Now().Add(d)})
Copy link
Contributor

Choose a reason for hiding this comment

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

thought - if we have this here, are we still coupling ourselves to proto?

Copy link
Contributor

Choose a reason for hiding this comment

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

(maybe fine?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes we are.. I feel that's fine.

livesql/live.go Outdated
@@ -75,7 +76,7 @@ func (t *dbTracker) processBinlog(update *update) {
}
}

func (t *dbTracker) registerDependency(ctx context.Context, table string, tester sqlgen.Tester) {
func (t *dbTracker) registerDependency(ctx context.Context, table string, tester sqlgen.Tester, filter sqlgen.Filter) error {
Copy link
Contributor

Choose a reason for hiding this comment

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

If we have the filter, do we need the tester to be passed in?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To build a tester, we need schema object. This change seems like the smallest change I can make

case float64:
return float64(v)
case time.Time:
return time.Time(v)
Copy link
Contributor

Choose a reason for hiding this comment

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

This handles more than driver.Value - for example, uint32 is not a driver.Value, only int64 is

@changpingc changpingc force-pushed the changping/serialize branch 4 times, most recently from 97c986c to e968849 Compare September 20, 2018 18:15
@changpingc changpingc changed the base branch from master to changping/value-filter September 20, 2018 18:15
…ncies

There are 2 kinds of dependencies in thunder we want to serialize:
reactive.InvalidateAt and livesql.Query. This commit creates protobuf
definitions for each type and their gogofast generated files.

The serialized dependencies are useful because we want to ship them
out of process to an external service.
This commit adds one required nil-able argument that is
the serializable form of the dependency. This argument
is collected in a dependency set which is accessable via
Dependencies(ctx) call.
This commit adds conversion between thunderpb.SQLFilter
and sqlgen.Tester. It assumes filter values are driver.Value
type for now, and we will relax that condition later.
@changpingc changpingc changed the base branch from changping/value-filter to master September 20, 2018 18:50
@changpingc
Copy link
Contributor Author

@berfarah I think this is ready to land! It should not introduce any additional error in existing API.

@berfarah
Copy link
Contributor

@changpingc given the amount of changes here, do you think a second pair of eyes might be useful?

Copy link
Contributor

@berfarah berfarah left a comment

Choose a reason for hiding this comment

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

Approving - though might be good to get some additional eyes from @stephen. The diff count on this PR is deceiving.

{
name: "id int64 ptr to int64",
filter: sqlgen.Filter{
"id": &one,
Copy link
Contributor

Choose a reason for hiding this comment

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

nil test case?

Copy link
Contributor

@zdylag zdylag left a comment

Choose a reason for hiding this comment

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

👍 Like the tests

@changpingc changpingc merged commit 3ff10eb into master Sep 20, 2018
@changpingc changpingc deleted the changping/serialize branch September 20, 2018 22:32
@changpingc changpingc restored the changping/serialize branch September 20, 2018 22:33
@changpingc changpingc deleted the changping/serialize branch September 20, 2018 22:34
Time = 8;
}

message Field {
Copy link

Choose a reason for hiding this comment

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

ahh, think I found what's causing a lot of cloudserver OOMs, I think this field is quite large and taking up much more memory than usual whenever we create a dependency.

Have we thought of using the proto oneof annotation here? Not sure if it actually reduces the allocation in code, just a thought.

Copy link

Choose a reason for hiding this comment

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

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants