-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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
instancestorage: read instances in a transaction #95800
instancestorage: read instances in a transaction #95800
Conversation
func (r *Reader) getAllUniqueLiveInstances( | ||
ctx context.Context, rows []instancerow, | ||
) ([]instancerow, error) { | ||
instancesSet := make(map[base.SQLInstanceID]struct{}, len(rows)) |
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.
I don't think this is needed. See the logic below after the sort.
instances, err := reader.GetAllInstances(ctx) | ||
if err != nil { | ||
return err | ||
} | ||
sortInstances(instances) | ||
return testOutputFn(instanceIDs, rpcAddresses, sqlAddresses, sessionIDs, localities, instances) | ||
if err := testOutputFn(instanceIDs, rpcAddresses, sqlAddresses, sessionIDs, localities, instances); err != nil { | ||
return err | ||
} | ||
instancesUsingTxn, err := getInstancesUsingTxnWrapper() | ||
if err != nil { | ||
return err | ||
} | ||
return testOutputFn(instanceIDs, rpcAddresses, sqlAddresses, sessionIDs, localities, instancesUsingTxn) |
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.
how about a helper to remove some of this boilerplate and to make the test easier to read?
Firstly, let's make a structure to pass to testOutputFn
, let's call it expectations
. Then, let's make a helper
type expectations struct { /* ... */ }
testOutputFn := func(exp expectations, actualInstances []sqlinstance.InstanceInfo) { /* ... */ }
expectationsFromOffset := func(offset int) expectations {
return expectations{
instanceIDs: instanceIDs[offset:],
rpcAddresses: rpcAddresses[offset:],
sqlAddresses: sqlAddresses[offset:],
sessionIDs: sessionIDs[offset:],
localities: localities[offset:]
}
}
// ...
verifyInstancesWithGetter := func(t *testing.T, name string, exp expectations, getInstances func()([]sqlinstance.InstanceInfo, error)) (retErr error) {
defer func() { errors.Wrap(retErr, name) }
instances, err := getInstances()
if err != nil {
return err
}
sortInstances(instances)
return testOutputFn(exp, instances)
}
verifyInstances := func(t *testing.T, exp expectations) {
if err := verifyInstancesWithGetter(t, "reader", offset, func() ([]sqlinstance.InstanceInfo, error) {
return reader.GetAllInstances(ctx)
}); err != nil {
return err
}
return verifyInstancesWithGetter(t, "txn", offset, func() ([]sqlinstance.InstanceInfo, error) {
return getInstancesUsingTxn(t)
})
}
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.
Nice
@@ -175,6 +175,15 @@ func TestReader(t *testing.T) { | |||
} | |||
return nil | |||
} | |||
getInstancesUsingTxnWrapper := func() ([]sqlinstance.InstanceInfo, error) { |
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.
nit: you should take t
as a parameter to deal with future refactorings and subtests. Also, I don't think the Wrapper
suffix adds value; just call it getInstancedUsingTxn
@@ -175,6 +175,15 @@ func TestReader(t *testing.T) { | |||
} | |||
return nil | |||
} | |||
getInstancesUsingTxnWrapper := func() ([]sqlinstance.InstanceInfo, error) { | |||
txn := s.DB().NewTxn(ctx, "testing GetAllInstancesUsingTxn") |
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.
NewTxn
is low-level and generally to be avoided. Instead you ought to use s.DB().Txn
if err != nil { | ||
return nil, err | ||
} | ||
sortInstances(instancesUsingTxn) |
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.
leave this for later. It'll make the next helper simpler.
068e40e
to
694d363
Compare
Ready for a second pass |
694d363
to
07111ed
Compare
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.
LGTM, the comments are all nits
instances := make([]sqlinstance.InstanceInfo, 0, len(rows)) | ||
for _, row := range filteredRows { | ||
instanceInfo := sqlinstance.InstanceInfo{ | ||
InstanceID: row.instanceID, | ||
InstanceRPCAddr: row.rpcAddr, | ||
InstanceSQLAddr: row.sqlAddr, | ||
SessionID: row.sessionID, | ||
Locality: row.locality, | ||
} | ||
instances = append(instances, instanceInfo) | ||
} | ||
return instances, nil |
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.
nit: extract a helper to convert the []instancerow
into []sqlinstance.InstanceInfo
. I'd probably also extract a constructor for a single InstanceInfo from a row like makeInstanceInfo(row instancerow) sqlinstance.InstanceInfo
so that is' like:
func makeInstanceInfos(rows []instancerow) []sqlinstance.InstanceInfo {
ret := make([]sqlinstance.InstanceInfo, len(rows))
for i := range rows {
ret[i] = makeInstanceInfo(rows[i])
}
return ret
}
@@ -225,8 +264,9 @@ func (r *Reader) GetAllInstances( | |||
return sqlInstances, nil | |||
} | |||
|
|||
func (r *Reader) getAllLiveInstances(ctx context.Context) ([]instancerow, error) { | |||
rows := r.getAllInstanceRows() | |||
func (r *Reader) getAllUniqueLiveInstances( |
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.
uber-nit: I think I'd take this off of the *Reader
and make it a free standing function which takes a sqlliveness.Reader
. I'd probably call it selectDistinctLiveRows(context.Context, sqlliveness.Reader, []instanceRow) ([]instancerow, error)
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.
Note also that the function will modify the slice in place.
// GetAllInstancesUsingTxn reads all instances using the given transaction and returns | ||
// live instances only. | ||
func (r *Reader) GetAllInstancesUsingTxn( | ||
ctx context.Context, tenantCodec keys.SQLCodec, tableID catid.DescID, txn *kv.Txn, |
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.
nit: everywhere else we just call this codec
} | ||
sortInstances(instances) | ||
return testOutputFn( | ||
return verifyInstances(t, expectations{ |
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.
I'd expect the linter to want field names, generally our style is to write them
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.
I don't think we lint against that although it'd be nice. I didn't add them initially because I assumed the types would be enough.
07111ed
to
df9ff31
Compare
TFTR! |
This code change adds `(instancestorage.Reader).GetAllInstancesUsingTxn` to read all instances using the given `*kv.Txn`. Release note: None Epic: CRDB-18735
df9ff31
to
b88b17c
Compare
bors r=ajwerner |
Build succeeded: |
This code change adds
(instancestorage.Reader).GetAllInstancesUsingTxn
to read all instances using the given*kv.Txn
.Release note: None
Epic: CRDB-18735