@@ -87,30 +87,62 @@ func (p *Parser) Parse(buf []byte, slist *types.SampleList) error {
8787 totalLen := len (buf )
8888
8989 for offset < totalLen {
90- // Find next delimiter position relative to current offset
91- relIdxHelp := bytes .Index (buf [offset :], helpHeader )
92- relIdxType := bytes .Index (buf [offset :], typeHeader )
90+ // Find next delimiter starting strictly AFTER 'offset'
91+ // We use IndexByte ('#') for performance (O(N) total scan instead of O(N^2))
92+ // and then verify if it's actually a header.
93+
94+ rest := buf [offset :]
95+
96+ // If we are at the very beginning of a block (or file), we might be standing ON a delimiter.
97+ // If so, we need to skip it to find the NEXT one.
98+ searchStart := 0
99+ if bytes .HasPrefix (rest , helpHeader ) {
100+ searchStart = len (helpHeader )
101+ } else if bytes .HasPrefix (rest , typeHeader ) {
102+ searchStart = len (typeHeader )
103+ }
93104
94- var relIdx int
105+ idx := - 1
106+ scanOffset := searchStart
95107
96- if relIdxHelp == - 1 && relIdxType == - 1 {
97- // No more delimiters, take the rest
98- relIdx = totalLen - offset
99- } else if relIdxHelp != - 1 && (relIdxType == - 1 || relIdxHelp < relIdxType ) {
100- relIdx = relIdxHelp
101- } else {
102- relIdx = relIdxType
108+ for {
109+ // Fast scan for '#'
110+ p := bytes .IndexByte (rest [scanOffset :], '#' )
111+ if p == - 1 {
112+ idx = - 1
113+ break
114+ }
115+
116+ // Potential delimiter found at relative index (scanOffset + p)
117+ candidate := rest [scanOffset + p :]
118+
119+ // Verify if it is indeed a header
120+ if bytes .HasPrefix (candidate , helpHeader ) || bytes .HasPrefix (candidate , typeHeader ) {
121+ idx = scanOffset + p
122+ break
123+ }
124+
125+ // False alarm (e.g. '#' inside a label or comment), continue scanning
126+ scanOffset += p + 1
103127 }
104128
105129 // Calculate absolute end of current chunk
130+ var relIdx int
131+ if idx == - 1 {
132+ relIdx = len (rest )
133+ } else {
134+ relIdx = idx
135+ }
136+
106137 chunkEnd := offset + relIdx
107138
139+ // Process current chunk if not empty
108140 if chunkEnd > offset {
109141 chunk := buf [offset :chunkEnd ]
110142 // Trim only leading/trailing whitespace to check for empty content
111143 if len (bytes .TrimSpace (chunk )) > 0 {
112144 // Handle "info" type check and replacement for each chunk
113- // "info->gauge" replacement feature
145+ // This ensures we support the legacy "info->gauge" replacement feature
114146 // We do Contains check first to avoid allocation if replacement isn't needed (Zero-Copy path)
115147 if bytes .Contains (chunk , infoBytes ) {
116148 chunk = bytes .ReplaceAll (chunk , infoBytes , gaugeBytes )
@@ -171,4 +203,4 @@ func getNameAndValue(m *dto.Metric, metricName string) map[string]interface{} {
171203 }
172204 }
173205 return fields
174- }
206+ }
0 commit comments