// SimpleThreadSafeTree is a thread safe radix tree that holds T.
type SimpleThreadSafeTree[T any] struct {
- mu *sync.RWMutex
- noLock bool
- tree *radix.Tree
- zero T
+ mu *sync.RWMutex
+ tree *radix.Tree
+ zero T
}
var noopFunc = func() {}
-func (tree *SimpleThreadSafeTree[T]) readLock() func() {
- if tree.noLock {
- return noopFunc
- }
- tree.mu.RLock()
- return tree.mu.RUnlock
-}
-
-func (tree *SimpleThreadSafeTree[T]) writeLock() func() {
- if tree.noLock {
- return noopFunc
- }
- tree.mu.Lock()
- return tree.mu.Unlock
-}
-
func (tree *SimpleThreadSafeTree[T]) Get(s string) T {
- unlock := tree.readLock()
- defer unlock()
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
if v, ok := tree.tree.Get(s); ok {
return v.(T)
}
func (tree *SimpleThreadSafeTree[T]) LongestPrefix(s string) (string, T) {
- unlock := tree.readLock()
- defer unlock()
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
if s, v, ok := tree.tree.LongestPrefix(s); ok {
return s, v.(T)
}
func (tree *SimpleThreadSafeTree[T]) Insert(s string, v T) T {
- unlock := tree.writeLock()
- defer unlock()
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
tree.tree.Insert(s, v)
return v
return noopFunc
}
-func (tree SimpleThreadSafeTree[T]) LockTree(lockType LockType) (TreeThreadSafe[T], func()) {
- unlock := tree.Lock(lockType)
- tree.noLock = true
- return &tree, unlock // create a copy of tree with the noLock flag set to true.
-}
-
func (tree *SimpleThreadSafeTree[T]) WalkPrefix(lockType LockType, s string, f func(s string, v T) (bool, error)) error {
commit := tree.Lock(lockType)
defer commit()
--- /dev/null
+// Copyright 2025 The Hugo Authors. All rights reserved.
+//
+// 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
+// http://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 doctree
+
+import (
+ "fmt"
+ "testing"
+)
+
+func BenchmarkSimpleThreadSafeTree(b *testing.B) {
+ newTestTree := func() TreeThreadSafe[int] {
+ t := NewSimpleThreadSafeTree[int]()
+ for i := 0; i < 1000; i++ {
+ t.Insert(fmt.Sprintf("key%d", i), i)
+ }
+ return t
+ }
+
+ b.Run("Get", func(b *testing.B) {
+ t := newTestTree()
+ b.ResetTimer()
+ for b.Loop() {
+ t.Get("key500")
+ }
+ })
+
+ b.Run("Insert", func(b *testing.B) {
+ t := newTestTree()
+ b.ResetTimer()
+ for b.Loop() {
+ t.Insert("key500", 501)
+ }
+ })
+
+ b.Run("LongestPrefix", func(b *testing.B) {
+ t := newTestTree()
+ b.ResetTimer()
+ for b.Loop() {
+ t.LongestPrefix("key500extra")
+ }
+ })
+}