-
Notifications
You must be signed in to change notification settings - Fork 18.4k
Closed
Labels
NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone
Description
In debugging the performance of Camlistore start-up (which slurps the index from disk to memory), I compared two popular MySQL drivers' allocations. Even the one that was being careful to not allocate (go-mysql-driver) was still allocating memory proportional to the data size (169.55 bytes in MysQL and 153.36 allocated): 2013/12/09 03:32:55 2512532 rows, 177786156 bytes; took 2.375200197s, 945ns each, 71.38 MB/s 2013/12/09 03:32:55 allocated = 160809408 I look into where the allocations were coming from. In the go-mysql-driver's Rows.Next (http://golang.org/pkg/database/sql/driver/#Rows) call: . 153.5 597: dest[i], isNull, n, err = readLengthEncodedString(data[pos:]) .... . . 45d2bd: MOVQ AX,18(SP) . 153.5 45d2c2: CALL runtime.convT2E(SB) It's exclusively from runtime.convT2E calls, assigning a []byte to an interface{} (driver.Value) 160809408 bytes / 2512532 rows / 2 columns = 32 bytes allocated per scanned string []byte column, even when the user of database/sql is trying to reduce allocations with sql.RawBytes. Proposal: Right now, the http://golang.org/pkg/database/sql/driver/#Rows Next method's dest []Value slice is purely an output that the driver is expected to write into. If we change it to also be an optional input to the driver, we could supply it with *[]byte and drivers can either work as they do today and write to dest, or new/updated drivers can notice a *[]byte in dest and instead using that pointer to assign directly, and signal that they've done so with a sentinel value: *(dest[i]) = rawByteSlice dest[i] = driver.SentinelValue driver.SentinelValue can be a pointer, so it fits into the empty interface without allocation. The only other driver.Value type (http://golang.org/pkg/database/sql/driver/#Value) that is bigger than a word is time.Time. If we care about that (and perhaps we should), we could extend this and say that instead of a *[]byte being supplied in the dest slice of []driver.Value, we instead populate it with *Sink pointers. package driver type Sink struct { .... } func (s *Sink) SetBytes(b []byte) { ... } func (s *Sink) SetTime(t time.Time) And then calling a Set method on a Sink replaces the need to have a sentinel value. If we do this, all existing drivers are still compatible. New drivers can type-assert for the *driver.Sink and call the Set method instead.
mitar
Metadata
Metadata
Assignees
Labels
NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.