github.com/minio/simdjson-go@v0.4.6-0.20231116094823-04d21cddf993/parse_json_amd64.go (about) 1 //go:build !noasm && !appengine && gc 2 // +build !noasm,!appengine,gc 3 4 /* 5 * MinIO Cloud Storage, (C) 2020 MinIO, Inc. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 20 package simdjson 21 22 import ( 23 "bytes" 24 "errors" 25 "sync" 26 ) 27 28 func (pj *internalParsedJson) initialize(size int) { 29 // Estimate the tape size to be about 15% of the length of the JSON message 30 avgTapeSize := size * 15 / 100 31 if cap(pj.Tape) < avgTapeSize { 32 pj.Tape = make([]uint64, 0, avgTapeSize) 33 } 34 pj.Tape = pj.Tape[:0] 35 36 stringsSize := size / 10 37 if stringsSize < 128 { 38 stringsSize = 128 // always allocate at least 128 for the string buffer 39 } 40 if pj.Strings != nil && cap(pj.Strings.B) >= stringsSize { 41 pj.Strings.B = pj.Strings.B[:0] 42 } else { 43 pj.Strings = &TStrings{make([]byte, 0, stringsSize)} 44 } 45 if cap(pj.containingScopeOffset) < maxdepth { 46 pj.containingScopeOffset = make([]uint64, 0, maxdepth) 47 } 48 pj.containingScopeOffset = pj.containingScopeOffset[:0] 49 pj.indexesChan = indexChan{} 50 } 51 52 func (pj *internalParsedJson) parseMessage(msg []byte, ndjson bool) (err error) { 53 // Cache message so we can point directly to strings 54 // TODO: Find out why TestVerifyTape/instruments fails without bytes.TrimSpace 55 pj.Message = bytes.TrimSpace(msg) 56 pj.initialize(len(pj.Message)) 57 58 if ndjson { 59 pj.ndjson = 1 60 } else { 61 pj.ndjson = 0 62 } 63 64 // Make the capacity of the channel smaller than the number of slots. 65 // This way the sender will automatically block until the consumer 66 // has finished the slot it is working on. 67 if pj.indexChans == nil { 68 pj.indexChans = make(chan indexChan, indexSlots-2) 69 } 70 pj.buffersOffset = ^uint64(0) 71 72 var errStage1 error 73 74 // Do long inputs async 75 if len(pj.Message) > 8<<10 { 76 var wg sync.WaitGroup 77 wg.Add(1) 78 go func() { 79 defer wg.Done() 80 if ok, done := pj.unifiedMachine(); !ok { 81 err = errors.New("Bad parsing while executing stage 2") 82 // Keep consuming... 83 if !done { 84 for idx := range pj.indexChans { 85 if idx.index == -1 { 86 break 87 } 88 } 89 } 90 } 91 }() 92 if !pj.findStructuralIndices() { 93 errStage1 = errors.New("Failed to find all structural indices for stage 1") 94 } 95 wg.Wait() 96 } else { 97 if !pj.findStructuralIndices() { 98 // drain the channel until empty 99 for idx := range pj.indexChans { 100 if idx.index == -1 { 101 break 102 } 103 } 104 return errors.New("Failed to find all structural indices for stage 1") 105 } 106 if ok, _ := pj.unifiedMachine(); !ok { 107 // drain the channel until empty 108 for { 109 select { 110 case idx := <-pj.indexChans: 111 if idx.index == -1 { 112 return errors.New("Bad parsing while executing stage 2") 113 } 114 // Already drained. 115 default: 116 return errors.New("Bad parsing while executing stage 2") 117 } 118 } 119 } 120 return nil 121 } 122 123 if errStage1 != nil { 124 return errStage1 125 } 126 return 127 }