Skip to content

Commit

Permalink
sa: truncate times in type converter (#7556)
Browse files Browse the repository at this point in the history
We believe the MariaDB query planner generates inefficient query plans
when a time index is queried using high precision (nanosecond) times.
This uses the updated borp from[1] to automatically truncate
`time.Time` and `*time.Time` in query parameters.

[1]: letsencrypt/borp#11

Part of #5437
  • Loading branch information
jsha authored Jun 24, 2024
1 parent 805ae53 commit c0ffbac
Show file tree
Hide file tree
Showing 11 changed files with 317 additions and 10 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ require (
github.com/google/certificate-transparency-go v1.1.6
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
github.com/jmhodges/clock v1.2.0
github.com/letsencrypt/borp v0.0.0-20230707160741-6cc6ce580243
github.com/letsencrypt/borp v0.0.0-20240620175310-a78493c6e2bd
github.com/letsencrypt/challtestsrv v1.2.1
github.com/letsencrypt/pkcs11key/v4 v4.0.0
github.com/letsencrypt/validator/v10 v10.0.0-20230215210743-a0c7dfc17158
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -150,14 +150,16 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/letsencrypt/borp v0.0.0-20230707160741-6cc6ce580243 h1:xS2U6PQYRURk61YN4Y5xvyLbQVyAP/8fpE6hJZdwEWs=
github.com/letsencrypt/borp v0.0.0-20230707160741-6cc6ce580243/go.mod h1:podMDq5wDu2ZO6JMKYQcjD3QdqOfNLWtP2RDSy8CHUU=
github.com/letsencrypt/borp v0.0.0-20240620175310-a78493c6e2bd h1:3c+LdlAOEcW1qmG8gtkMCyAEoslmj6XCmniB+926kMM=
github.com/letsencrypt/borp v0.0.0-20240620175310-a78493c6e2bd/go.mod h1:gMSMCNKhxox/ccR923EJsIvHeVVYfCABGbirqa0EwuM=
github.com/letsencrypt/challtestsrv v1.2.1 h1:Lzv4jM+wSgVMCeO5a/F/IzSanhClstFMnX6SfrAJXjI=
github.com/letsencrypt/challtestsrv v1.2.1/go.mod h1:Ur4e4FvELUXLGhkMztHOsPIsvGxD/kzSJninOrkM+zc=
github.com/letsencrypt/pkcs11key/v4 v4.0.0 h1:qLc/OznH7xMr5ARJgkZCCWk+EomQkiNTOoOF5LAgagc=
github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag=
github.com/letsencrypt/validator/v10 v10.0.0-20230215210743-a0c7dfc17158 h1:HGFsIltYMUiB5eoFSowFzSoXkocM2k9ctmJ57QMGjys=
github.com/letsencrypt/validator/v10 v10.0.0-20230215210743-a0c7dfc17158/go.mod h1:ZFNBS3H6OEsprCRjscty6GCBe5ZiX44x6qY4s7+bDX0=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
Expand Down
13 changes: 13 additions & 0 deletions sa/type-converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"
"errors"
"fmt"
"time"

"github.com/go-jose/go-jose/v4"

Expand Down Expand Up @@ -35,6 +36,18 @@ func (tc BoulderTypeConverter) ToDb(val interface{}) (interface{}, error) {
return string(t), nil
case core.OCSPStatus:
return string(t), nil
// Time types get truncated to the nearest second. Given our DB schema,
// only seconds are stored anyhow. Avoiding sending queries with sub-second
// precision may help the query planner avoid pathological cases when
// querying against indexes on time fields (#5437).
case time.Time:
return t.Truncate(time.Second), nil
case *time.Time:
if t == nil {
return nil, nil
}
newT := t.Truncate(time.Second)
return &newT, nil
default:
return val, nil
}
Expand Down
24 changes: 24 additions & 0 deletions sa/type-converter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package sa
import (
"encoding/json"
"testing"
"time"

"github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/identifier"
Expand Down Expand Up @@ -151,3 +152,26 @@ func TestStringSlice(t *testing.T) {
test.AssertNotError(t, err, "failed to scanner.Binder")
test.AssertMarshaledEquals(t, au, out)
}

func TestTimeTruncate(t *testing.T) {
tc := BoulderTypeConverter{}
preciseTime := time.Date(2024, 06, 20, 00, 00, 00, 999999999, time.UTC)
dbTime, err := tc.ToDb(preciseTime)
test.AssertNotError(t, err, "Could not ToDb")
dbTimeT, ok := dbTime.(time.Time)
test.Assert(t, ok, "Could not convert dbTime to time.Time")
test.Assert(t, dbTimeT.Nanosecond() == 0, "Nanosecond not truncated")

dbTimePtr, err := tc.ToDb(&preciseTime)
test.AssertNotError(t, err, "Could not ToDb")
dbTimePtrT, ok := dbTimePtr.(*time.Time)
test.Assert(t, ok, "Could not convert dbTimePtr to *time.Time")
test.Assert(t, dbTimePtrT.Nanosecond() == 0, "Nanosecond not truncated")

var dbTimePtrNil *time.Time
shouldBeNil, err := tc.ToDb(dbTimePtrNil)
test.AssertNotError(t, err, "Could not ToDb")
if shouldBeNil != nil {
t.Errorf("Expected nil, got %v", shouldBeNil)
}
}
45 changes: 42 additions & 3 deletions vendor/github.com/letsencrypt/borp/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

74 changes: 74 additions & 0 deletions vendor/github.com/letsencrypt/borp/db.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion vendor/github.com/letsencrypt/borp/dialect.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit c0ffbac

Please sign in to comment.