2022-11-01 13:24:32 -05:00
|
|
|
package sqlstore
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"reflect"
|
|
|
|
|
|
|
|
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
|
|
|
)
|
|
|
|
|
|
|
|
const DefaultBatchSize = 1000
|
|
|
|
|
|
|
|
type BulkOpSettings struct {
|
|
|
|
BatchSize int
|
|
|
|
}
|
|
|
|
|
|
|
|
func NativeSettingsForDialect(d migrator.Dialect) BulkOpSettings {
|
|
|
|
return BulkOpSettings{
|
|
|
|
BatchSize: d.BatchSize(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func normalizeBulkSettings(s BulkOpSettings) BulkOpSettings {
|
|
|
|
if s.BatchSize < 1 {
|
|
|
|
sessionLogger.Debug("Invalid batch size, falling back to the default", "requested", s.BatchSize, "actual", DefaultBatchSize)
|
|
|
|
s.BatchSize = DefaultBatchSize
|
|
|
|
}
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
2023-08-30 10:46:47 -05:00
|
|
|
func (sess *DBSession) BulkInsert(table any, recordsSlice any, opts BulkOpSettings) (int64, error) {
|
2022-11-01 13:24:32 -05:00
|
|
|
var inserted int64
|
2023-08-30 10:46:47 -05:00
|
|
|
err := InBatches(recordsSlice, opts, func(batch any) error {
|
2022-11-01 13:24:32 -05:00
|
|
|
a, err := sess.Table(table).InsertMulti(batch)
|
|
|
|
inserted += a
|
|
|
|
return err
|
|
|
|
})
|
|
|
|
return inserted, err
|
|
|
|
}
|
|
|
|
|
2023-08-30 10:46:47 -05:00
|
|
|
func InBatches(items any, opts BulkOpSettings, fn func(batch any) error) error {
|
2022-11-01 13:24:32 -05:00
|
|
|
opts = normalizeBulkSettings(opts)
|
|
|
|
slice := reflect.Indirect(reflect.ValueOf(items))
|
|
|
|
if slice.Kind() != reflect.Slice {
|
|
|
|
return fmt.Errorf("need a slice of objects in order to batch")
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; i < slice.Len(); i += opts.BatchSize {
|
|
|
|
end := i + opts.BatchSize
|
|
|
|
if end > slice.Len() {
|
|
|
|
end = slice.Len()
|
|
|
|
}
|
|
|
|
|
|
|
|
chunk := slice.Slice(i, end).Interface()
|
|
|
|
|
|
|
|
if err := fn(chunk); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|