Skip to content

Commit

Permalink
ci: norace test
Browse files Browse the repository at this point in the history
  • Loading branch information
AsterDY committed Jun 26, 2024
1 parent 7b92858 commit 2c4dbb2
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 145 deletions.
2 changes: 1 addition & 1 deletion ast/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -800,7 +800,7 @@ func (self *Node) AddAny(val interface{}) error {
// Note, the api expects the json is well-formed at least,
// otherwise it may return unexpected result.
func (self *Node) GetByPath(path ...interface{}) *Node {
if self.checkRaw() != nil {
if !self.Valid() {
return self
}
var s = self
Expand Down
176 changes: 88 additions & 88 deletions ast/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,86 +299,6 @@ func (self *Parser) Pos() int {
return self.p
}

// Parse returns a ast.Node representing the parser's JSON.
// NOTICE: the specific parsing lazy dependens parser's option
// It only parse first layer and first child for Object or Array be default
func (self *Parser) Parse() (Node, types.ParsingError) {
switch val := self.decodeValue(); val.Vt {
case types.V_EOF : return Node{}, types.ERR_EOF
case types.V_NULL : return nullNode, 0
case types.V_TRUE : return trueNode, 0
case types.V_FALSE : return falseNode, 0
case types.V_STRING : return self.decodeString(val.Iv, val.Ep)
case types.V_ARRAY:
s := self.p - 1;
if p := skipBlank(self.s, self.p); p >= self.p && self.s[p] == ']' {
self.p = p + 1
return Node{t: types.V_ARRAY}, 0
}
if self.noLazy {
return self.decodeArray(new(linkedNodes))
}
if noLazy {
self.p = s
s, e := self.skipFast()
if e != 0 {
return Node{}, e
}
return newRawNode(self.s[s:self.p], types.V_ARRAY), 0
}
return newLazyArray(self), 0
case types.V_OBJECT:
s := self.p - 1;
if p := skipBlank(self.s, self.p); p >= self.p && self.s[p] == '}' {
self.p = p + 1
return Node{t: types.V_OBJECT}, 0
}
if self.noLazy {
return self.decodeObject(new(linkedPairs))
}
if noLazy {
self.p = s
s, e := self.skipFast()
if e != 0 {
return Node{}, e
}
return newRawNode(self.s[s:self.p], types.V_OBJECT), 0
}
return newLazyObject(self), 0
case types.V_DOUBLE : return NewNumber(self.s[val.Ep:self.p]), 0
case types.V_INTEGER : return NewNumber(self.s[val.Ep:self.p]), 0
default : return Node{}, types.ParsingError(-val.Vt)
}
}

// Parse returns a ast.Node representing the parser's JSON.
// NOTICE: the specific parsing lazy dependens parser's option
// It only parse first layer and all chidren for Object or Array by default
func (self *Parser) ParseNoLazy() (Node, types.ParsingError) {
switch val := self.decodeValue(); val.Vt {
case types.V_EOF : return Node{}, types.ERR_EOF
case types.V_NULL : return nullNode, 0
case types.V_TRUE : return trueNode, 0
case types.V_FALSE : return falseNode, 0
case types.V_STRING : return self.decodeString(val.Iv, val.Ep)
case types.V_ARRAY:
if p := skipBlank(self.s, self.p); p >= self.p && self.s[p] == ']' {
self.p = p + 1
return Node{t: types.V_ARRAY}, 0
}
return self.decodeArray(new(linkedNodes))
case types.V_OBJECT:
if p := skipBlank(self.s, self.p); p >= self.p && self.s[p] == '}' {
self.p = p + 1
return Node{t: types.V_OBJECT}, 0
}
return self.decodeObject(new(linkedPairs))
case types.V_DOUBLE : return NewNumber(self.s[val.Ep:self.p]), 0
case types.V_INTEGER : return NewNumber(self.s[val.Ep:self.p]), 0
default : return Node{}, types.ParsingError(-val.Vt)
}
}

func (self *Node) skipNextNode() *Node {
if !self.isLazy() {
return nil
Expand Down Expand Up @@ -599,6 +519,86 @@ func backward(src string, i int) int {
}


// Parse returns a ast.Node representing the parser's JSON.
// NOTICE: the specific parsing lazy dependens parser's option
// It only parse first layer and first child for Object or Array be default
func (self *Parser) Parse() (Node, types.ParsingError) {
switch val := self.decodeValue(); val.Vt {
case types.V_EOF : return Node{}, types.ERR_EOF
case types.V_NULL : return nullNode, 0
case types.V_TRUE : return trueNode, 0
case types.V_FALSE : return falseNode, 0
case types.V_STRING : return self.decodeString(val.Iv, val.Ep)
case types.V_ARRAY:
s := self.p - 1;
if p := skipBlank(self.s, self.p); p >= self.p && self.s[p] == ']' {
self.p = p + 1
return Node{t: types.V_ARRAY}, 0
}
if self.noLazy {
return self.decodeArray(new(linkedNodes))
}
if noLazy {
self.p = s
s, e := self.skipFast()
if e != 0 {
return Node{}, e
}
return newRawNode(self.s[s:self.p], types.V_ARRAY), 0
}
return newLazyArray(self), 0
case types.V_OBJECT:
s := self.p - 1;
if p := skipBlank(self.s, self.p); p >= self.p && self.s[p] == '}' {
self.p = p + 1
return Node{t: types.V_OBJECT}, 0
}
if self.noLazy {
return self.decodeObject(new(linkedPairs))
}
if noLazy {
self.p = s
s, e := self.skipFast()
if e != 0 {
return Node{}, e
}
return newRawNode(self.s[s:self.p], types.V_OBJECT), 0
}
return newLazyObject(self), 0
case types.V_DOUBLE : return NewNumber(self.s[val.Ep:self.p]), 0
case types.V_INTEGER : return NewNumber(self.s[val.Ep:self.p]), 0
default : return Node{}, types.ParsingError(-val.Vt)
}
}

// Parse returns a ast.Node representing the parser's JSON.
// NOTICE: the specific parsing lazy dependens parser's option
// It only parse first layer and all chidren for Object or Array by default
func (self *Parser) ParseNoLazy() (Node, types.ParsingError) {
switch val := self.decodeValue(); val.Vt {
case types.V_EOF : return Node{}, types.ERR_EOF
case types.V_NULL : return nullNode, 0
case types.V_TRUE : return trueNode, 0
case types.V_FALSE : return falseNode, 0
case types.V_STRING : return self.decodeString(val.Iv, val.Ep)
case types.V_ARRAY:
if p := skipBlank(self.s, self.p); p >= self.p && self.s[p] == ']' {
self.p = p + 1
return Node{t: types.V_ARRAY}, 0
}
return self.decodeArray(new(linkedNodes))
case types.V_OBJECT:
if p := skipBlank(self.s, self.p); p >= self.p && self.s[p] == '}' {
self.p = p + 1
return Node{t: types.V_OBJECT}, 0
}
return self.decodeObject(new(linkedPairs))
case types.V_DOUBLE : return NewNumber(self.s[val.Ep:self.p]), 0
case types.V_INTEGER : return NewNumber(self.s[val.Ep:self.p]), 0
default : return Node{}, types.ParsingError(-val.Vt)
}
}

func newRawNode(str string, typ types.ValueType) Node {
ret := Node{
t: _V_RAW | typ,
Expand Down Expand Up @@ -669,25 +669,25 @@ func switchRawType(c byte) types.ValueType {


func (self *Node) lock() {
// if self.m != nil {
if self.m != nil {
self.m.Lock()
// }
}
}

func (self *Node) unlock() {
// if self.m != nil {
if self.m != nil {
self.m.Unlock()
// }
}
}

func (self *Node) rlock() {
// if self.m != nil {
if self.m != nil {
self.m.RLock()
// }
}
}

func (self *Node) runlock() {
// if self.m != nil {
if self.m != nil {
self.m.RUnlock()
// }
}
}
75 changes: 75 additions & 0 deletions ast/parser_norace_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//go:build !race

// Copyright 2024 CloudWeGo Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ast

import (
"sync"
"testing"

"github.com/stretchr/testify/require"
)


func TestParseNoLazy(t *testing.T) {
noLazy = true

src := `{"1":1,"2": [ 1 , 2 , { "3" : 3 } ] }`
node := NewRaw(src)

cases := []struct{
path []interface{}
exp []string
}{
{[]interface{}{"1"}, []string{`1`}},
{[]interface{}{"2"}, []string{`[ 1 , 2 , { "3" : 3 } ]`, `[1,2,{ "3" : 3 }]`, `[1,2,{"3":3}]`}},
{[]interface{}{"2", 1}, []string{`2`}},
{[]interface{}{"2", 2}, []string{`{ "3" : 3 }`, `{"3":3}`}},
{[]interface{}{"2", 2, "3"}, []string{`3`}},
}

wg := sync.WaitGroup{}
start := sync.RWMutex{}
start.Lock()

P := 1000
for i := range cases {
// println(i)
c := cases[i]
for j := 0; j < P; j++ {
wg.Add(1)
go func () {
defer wg.Done()
start.RLock()
v, err := node.GetByPath(c.path...).Raw()
require.NoError(t, err)
eq := false
for _, exp := range c.exp {
if exp == v {
eq = true
break
}
}
require.True(t, eq)
}()
}
}

start.Unlock()
wg.Wait()

noLazy = false
}
73 changes: 17 additions & 56 deletions ast/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,64 +31,9 @@ import (

var (
debugSyncGC = os.Getenv("SONIC_SYNC_GC") != ""
debugAsyncGC = os.Getenv("SONIC_NO_ASYNC_GC") != ""
debugAsyncGC = os.Getenv("SONIC_NO_ASYNC_GC") == ""
)

func TestParseNoLazy(t *testing.T) {
noLazy = true

src := `{"1":1,"2": [ 1 , 2 , { "3" : 3 } ] }`
node := NewRaw(src)

cases := []struct{
path []interface{}
exp []string
}{
{[]interface{}{"1"}, []string{`1`}},
{[]interface{}{"1"}, []string{`1`}},
// {[]interface{}{"2"}, []string{`[ 1 , 2 , { "3" : 3 } ]`, `[1,2,{ "3" : 3 }]`, `[1,2,{"3":3}]`}},
// {[]interface{}{"2"}, []string{`[ 1 , 2 , { "3" : 3 } ]`, `[1,2,{ "3" : 3 }]`, `[1,2,{"3":3}]`}},
// {[]interface{}{"2"}, []string{`[ 1 , 2 , { "3" : 3 } ]`, `[1,2,{ "3" : 3 }]`, `[1,2,{"3":3}]`}},
// {[]interface{}{"2", 1}, []string{`2`}},
// {[]interface{}{"2", 1}, []string{`2`}},
// {[]interface{}{"2", 2}, []string{`{ "3" : 3 }`, `{"3":3}`}},
// {[]interface{}{"2", 2}, []string{`{ "3" : 3 }`, `{"3":3}`}},
// {[]interface{}{"2", 2}, []string{`{ "3" : 3 }`, `{"3":3}`}},
// {[]interface{}{"2", 2, "3"}, []string{`3`}},
// {[]interface{}{"2", 2, "3"}, []string{`3`}},
}

wg := sync.WaitGroup{}
start := sync.RWMutex{}
start.Lock()

for i := range cases {
println(i)
c := cases[i]
wg.Add(1)

go func () {
defer wg.Done()
start.RLock()
node.GetByPath(c.path...)
// require.NoError(t, err)
// eq := false
// for _, exp := range c.exp {
// if exp == v {
// eq = true
// break
// }
// }
// require.True(t, eq)
}()
}

start.Unlock()
wg.Wait()

noLazy = false
}

func TestMain(m *testing.M) {
go func () {
if !debugAsyncGC {
Expand Down Expand Up @@ -401,6 +346,22 @@ func BenchmarkParseNoLazy_Parallel_Sonic(b *testing.B) {
noLazy = false
}

func BenchmarkNodeRaw_Parallel_Sonic(b *testing.B) {
noLazy = true
b.SetBytes(int64(len(_TwitterJson)))
b.ResetTimer()
ast := NewRaw(_TwitterJson)
b.RunParallel(func(p *testing.PB) {
for p.Next() {
node := ast.GetByPath("statuses", 3)
if _, e := node.Raw(); e != nil {
b.Fatal(e)
}
}
})
noLazy = false
}

func BenchmarkParseSeven_Sonic(b *testing.B) {
b.SetBytes(int64(len(_TwitterJson)))
b.ResetTimer()
Expand Down

0 comments on commit 2c4dbb2

Please sign in to comment.