Skip to content

Instantly share code, notes, and snippets.

@berfarah
berfarah / sqlgen.go.diff
Created October 1, 2018 21:36
Iterative Optimization on Hot Paths: Optimization 4: Preventing escape of complex data types
func makeWhere(table *Table, filter Filter) (*SimpleWhere, error) {
for name, value := range filter {
// ...
- l = append(l, whereElem{column: column, value: column.Descriptor.Valuer(reflect.ValueOf(value))})
+ v, err := column.Descriptor.Valuer(reflect.ValueOf(value)).Value()
+ if err != nil {
+ return nil, err
+ }
+ l = append(l, whereElem{column: column, value: v})
}
@berfarah
berfarah / sqlgen.go.diff
Created October 1, 2018 21:34
Iterative Optimization on Hot Paths: Optimization 3: Re-use of allocations
func parseQueryRow(table *Table, rows *sql.Rows) (interface{}, error) {
// ...
- values := make([]interface{}, len(table.Columns))
+ values := table.Scanners.Get().([]interface{})
+ defer table.Scanners.Put(values)
for i, column := range table.Columns {
- scanner := column.Descriptor.Scanner()
- scanner.Target(field)
- values[i] = scanner
@berfarah
berfarah / sqlgen.go.diff
Created October 1, 2018 21:32
Iterative Optimization on Hot Paths: Optimization 2: Cutting out the middleman
func parseQueryRow(table *Table, rows *sql.Rows) (interface{}, error) {
ptr := reflect.New(table.Type)
elem := ptr.Elem()
values := make([]interface{}, len(table.Columns))
- [... populate scanners slice with column.Descriptor.Scanner() ...]
+ for i, column := range table.Columns {
+ scanner := column.Descriptor.Scanner()
+ scanner.Target(field)
+ values[i] = scanner
@berfarah
berfarah / scanner.go.diff
Created October 1, 2018 21:31
Iterative Optimization on Hot Paths: Optimization 2: Cutting out the middleman
// goodbye reflect.New in Scanner.Scan
func (s *Scanner) Scan(src interface{}) error {
- s.value = reflect.New(s.Type)
+ // Clear out the value after a scan so we aren't holding onto references.
+ defer func() { s.value = reflect.Value{} }()
// ...
}
// and hello Scanner.Target
+func (s *Scanner) Target(value reflect.Value) {
@berfarah
berfarah / descriptor.go.diff
Created October 1, 2018 21:27
Iterative Optimization on Hot Paths: Optimization 1: Pass by value
// Valuer creates a sql/driver.Valuer from the type and value.
-func (d Descriptor) Valuer(val reflect.Value) Valuer {
+func (d *Descriptor) Valuer(val reflect.Value) Valuer {
- return Valuer{Descriptor: &d, value: val}
+ return Valuer{Descriptor: d, value: val}
}
// Scanner creates a sql.Scanner from the descriptor.
-func (d Descriptor) Scanner() *Scanner { return &Scanner{Descriptor: &d} }
+func (d *Descriptor) Scanner() *Scanner { return &Scanner{Descriptor: d} }
@berfarah
berfarah / descriptor.go
Created October 1, 2018 21:24
Iterative Optimization on Hot Paths: Planning it out: Wrangling Go interfaces
type Descriptor struct {
Tags TagSet // struct tags
Type reflect.Type // the original type
Kind reflect.Kind // the underlying kind
Ptr bool // whether or not it's a ptr
}
@berfarah
berfarah / scanner.go
Created October 1, 2018 21:23
Iterative Optimization on Hot Paths: Planning it out: Wrangling Go interfaces
type Scanner interface {
// the docs tell us that the src will be a valid driver.Value
Scan(src interface{}) error
}
@berfarah
berfarah / valuer.go
Created October 1, 2018 21:22
Iterative Optimization on Hot Paths: Planning it out: Wrangling Go interfaces
type Valuer interface {
Value() (driver.Value, error)
}
@berfarah
berfarah / db_use.go
Created October 1, 2018 21:21
Iterative Optimization on Hot Paths: Planning it out: Wrangling Go interfaces
id := 5
var name string
err := db.QueryRowContext(ctx, "SELECT name FROM users WHERE id = ?", id).Scan(&name)
@berfarah
berfarah / users.go
Created October 1, 2018 21:19
Iterative Optimization on Hot Paths: Storing JSON in the database
type User struct {
ID int64 `sql:",primary"`
Name string
Configuration Configuration `sql:",json"`
}