Skip to content

Commit 1b7db65

Browse files
committed
skipping elements/documents when decoding to raw to speed up unmarshalling.
1 parent 1aa8d2b commit 1b7db65

File tree

1 file changed

+92
-46
lines changed

1 file changed

+92
-46
lines changed

bson/decode.go

Lines changed: 92 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -225,61 +225,65 @@ func (d *decoder) readDocTo(out reflect.Value) {
225225
panic("Unsupported document type for unmarshalling: " + out.Type().String())
226226
}
227227

228-
end := int(d.readInt32())
229-
end += d.i - 4
230-
if end <= d.i || end > len(d.in) || d.in[end-1] != '\x00' {
231-
corrupted()
232-
}
233-
for d.in[d.i] != '\x00' {
234-
kind := d.readByte()
235-
name := d.readCStr()
236-
if d.i >= end {
228+
if outt == typeRaw {
229+
d.skipDoc()
230+
} else {
231+
end := int(d.readInt32())
232+
end += d.i - 4
233+
if end <= d.i || end > len(d.in) || d.in[end-1] != '\x00' {
237234
corrupted()
238235
}
236+
for d.in[d.i] != '\x00' {
237+
kind := d.readByte()
238+
name := d.readCStr()
239+
if d.i >= end {
240+
corrupted()
241+
}
239242

240-
switch outk {
241-
case reflect.Map:
242-
e := reflect.New(elemType).Elem()
243-
if d.readElemTo(e, kind) {
244-
k := reflect.ValueOf(name)
245-
if convertKey {
246-
k = k.Convert(keyType)
243+
switch outk {
244+
case reflect.Map:
245+
e := reflect.New(elemType).Elem()
246+
if d.readElemTo(e, kind) {
247+
k := reflect.ValueOf(name)
248+
if convertKey {
249+
k = k.Convert(keyType)
250+
}
251+
out.SetMapIndex(k, e)
247252
}
248-
out.SetMapIndex(k, e)
249-
}
250-
case reflect.Struct:
251-
if outt == typeRaw {
252-
d.dropElem(kind)
253-
} else {
254-
if info, ok := fieldsMap[name]; ok {
255-
if info.Inline == nil {
256-
d.readElemTo(out.Field(info.Num), kind)
253+
case reflect.Struct:
254+
if outt == typeRaw {
255+
d.dropElem(kind)
256+
} else {
257+
if info, ok := fieldsMap[name]; ok {
258+
if info.Inline == nil {
259+
d.readElemTo(out.Field(info.Num), kind)
260+
} else {
261+
d.readElemTo(out.FieldByIndex(info.Inline), kind)
262+
}
263+
} else if inlineMap.IsValid() {
264+
if inlineMap.IsNil() {
265+
inlineMap.Set(reflect.MakeMap(inlineMap.Type()))
266+
}
267+
e := reflect.New(elemType).Elem()
268+
if d.readElemTo(e, kind) {
269+
inlineMap.SetMapIndex(reflect.ValueOf(name), e)
270+
}
257271
} else {
258-
d.readElemTo(out.FieldByIndex(info.Inline), kind)
272+
d.dropElem(kind)
259273
}
260-
} else if inlineMap.IsValid() {
261-
if inlineMap.IsNil() {
262-
inlineMap.Set(reflect.MakeMap(inlineMap.Type()))
263-
}
264-
e := reflect.New(elemType).Elem()
265-
if d.readElemTo(e, kind) {
266-
inlineMap.SetMapIndex(reflect.ValueOf(name), e)
267-
}
268-
} else {
269-
d.dropElem(kind)
270274
}
275+
case reflect.Slice:
271276
}
272-
case reflect.Slice:
273-
}
274277

275-
if d.i >= end {
278+
if d.i >= end {
279+
corrupted()
280+
}
281+
}
282+
d.i++ // '\x00'
283+
if d.i != end {
276284
corrupted()
277285
}
278286
}
279-
d.i++ // '\x00'
280-
if d.i != end {
281-
corrupted()
282-
}
283287
d.docType = docType
284288

285289
if outt == typeRaw {
@@ -431,7 +435,40 @@ func (d *decoder) readDocWith(f func(kind byte, name string)) {
431435
var blackHole = settableValueOf(struct{}{})
432436

433437
func (d *decoder) dropElem(kind byte) {
434-
d.readElemTo(blackHole, kind)
438+
switch kind {
439+
case 0x01, 0x09, 0x11, 0x12: // utc datetime, timestamp, int64
440+
d.i += 8
441+
case 0x02, 0x0D, 0x0E: // string, javascript, symbol
442+
size := int(d.readInt32())
443+
if size <= 0 || d.in[d.i+size-1] != 0x00 {
444+
corrupted()
445+
}
446+
d.i += size
447+
case 0x03, 0x04: // doc, array
448+
d.skipDoc()
449+
case 0x05: // binary
450+
size := int(d.readInt32())
451+
d.i += size + 1 // + 1 for the subtype
452+
case 0x06: // undefined
453+
case 0x07: // objectID
454+
d.i += 12
455+
case 0x08:
456+
d.i++
457+
case 0x0A: // null
458+
case 0x0B: // regex
459+
d.readCStr()
460+
d.readCStr()
461+
case 0x0C: // dbpointer
462+
size := int(d.readInt32())
463+
d.i += size + 12
464+
case 0x10: // int32
465+
d.i += 4
466+
case 0x13: // decimal
467+
d.i += 16
468+
case 0xFF, 0x7F: //min key, max key
469+
default:
470+
d.readElemTo(blackHole, kind)
471+
}
435472
}
436473

437474
// Attempt to decode an element from the document and put it into out.
@@ -461,11 +498,11 @@ func (d *decoder) readElemTo(out reflect.Value, kind byte) (good bool) {
461498
case typeRawDocElem:
462499
out.Set(d.readRawDocElems(outt))
463500
default:
464-
d.readDocTo(blackHole)
501+
d.skipDoc()
465502
}
466503
return true
467504
}
468-
d.readDocTo(blackHole)
505+
d.skipDoc()
469506
return true
470507
}
471508

@@ -748,6 +785,15 @@ func (d *decoder) readElemTo(out reflect.Value, kind byte) (good bool) {
748785
// --------------------------------------------------------------------------
749786
// Parsers of basic types.
750787

788+
func (d *decoder) skipDoc() {
789+
end := int(d.readInt32())
790+
end += d.i - 4
791+
if end <= d.i || end > len(d.in) || d.in[end-1] != '\x00' {
792+
corrupted()
793+
}
794+
d.i = end
795+
}
796+
751797
func (d *decoder) readRegEx() RegEx {
752798
re := RegEx{}
753799
re.Pattern = d.readCStr()

0 commit comments

Comments
 (0)