This is an automated email from the ASF dual-hosted git repository.
chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory.git
The following commit(s) were added to refs/heads/main by this push:
new a23b1cef7 refactor(go): Replace globalTypeResolver with factory-based
serializer registration (#2615)
a23b1cef7 is described below
commit a23b1cef7f121cae024806fc108b5e48d747170c
Author: thisingl <[email protected]>
AuthorDate: Tue Sep 16 14:01:40 2025 +0800
refactor(go): Replace globalTypeResolver with factory-based serializer
registration (#2615)
<!--
**Thanks for contributing to Apache Fory™.**
**If this is your first time opening a PR on fory, you can refer to
[CONTRIBUTING.md](https://github.com/apache/fory/blob/main/CONTRIBUTING.md).**
Contribution Checklist
- The **Apache Fory™** community has requirements on the naming of pr
titles. You can also find instructions in
[CONTRIBUTING.md](https://github.com/apache/fory/blob/main/CONTRIBUTING.md).
- Apache Fory™ has a strong focus on performance. If the PR you submit
will have an impact on performance, please benchmark it first and
provide the benchmark result here.
-->
## Why?
The current `globalTypeResolver` design has several issues:
- Maintains complex dual state management (global + per-instance)
- Every Fory instance creation requires copying entire global state
## What does this PR do?
Replaced the complex global state management with a lightweight factory
function registry
<!-- Describe the details of this PR. -->
#### Before (Complex Global State)
```go
// Heavy global state with full serializer instances
var globalTypeResolver *typeResolver
// Every instance copies all global state
func NewFory() {
for type_, serializer := range globalTypeResolver.typeToSerializers {
fory.typeResolver.typeToSerializers[type_] = serializer // Full
copy
}
}
```
#### After (Lightweight Factory Registry)
```go
// Lightweight global registry storing only factory functions
var generatedSerializerFactories = struct {
factories map[reflect.Type]func() Serializer
}
// Instance-level registration on demand
func newTypeResolver() {
for type_, factory := range generatedSerializerFactories.factories {
serializer := factory() // Create on demand
r.typeToSerializers[type_] = serializer // Register to
instance
}
}
```
## Related issues
<!--
Is there any related issue? If this PR closes them you say say
fix/closes:
- #xxxx0
- #xxxx1
- Fixes #xxxx2
-->
## Does this PR introduce any user-facing change?
<!--
If any user-facing interface changes, please [open an
issue](https://github.com/apache/fory/issues/new/choose) describing the
need to do so and update the document if necessary.
Delete section if not applicable.
-->
- [ ] Does this PR introduce any public API change?
- [ ] Does this PR introduce any binary protocol compatibility change?
## Benchmark
<!--
When the PR has an impact on performance (if you don't know whether the
PR will have an impact on performance, you can submit the PR first, and
if it will have impact on performance, the code reviewer will explain
it), be sure to attach a benchmark data here.
Delete section if not applicable.
-->
---
go/fory/codegen/generator.go | 13 +++--
go/fory/fory.go | 26 +---------
go/fory/type.go | 121 ++++++++++---------------------------------
3 files changed, 37 insertions(+), 123 deletions(-)
diff --git a/go/fory/codegen/generator.go b/go/fory/codegen/generator.go
index a2c236685..db50c0374 100644
--- a/go/fory/codegen/generator.go
+++ b/go/fory/codegen/generator.go
@@ -307,10 +307,10 @@ func generateCodeForFile(pkg *packages.Package, structs
[]*StructInfo, sourceFil
fmt.Fprintf(&buf, "\t\"github.com/apache/fory/go/fory\"\n")
fmt.Fprintf(&buf, ")\n\n")
- // Generate init function to register serializers
+ // Generate init function to register serializer factories
fmt.Fprintf(&buf, "func init() {\n")
for _, s := range structs {
- fmt.Fprintf(&buf,
"\tfory.RegisterGeneratedSerializer((*%s)(nil), %s_ForyGenSerializer{})\n",
s.Name, s.Name)
+ fmt.Fprintf(&buf, "\tfory.RegisterSerializerFactory((*%s)(nil),
NewSerializerFor_%s)\n", s.Name, s.Name)
}
fmt.Fprintf(&buf, "}\n\n")
@@ -393,6 +393,11 @@ func generateStructSerializer(buf *bytes.Buffer, s
*StructInfo) error {
// Generate struct serializer type
fmt.Fprintf(buf, "type %s_ForyGenSerializer struct {}\n\n", s.Name)
+ // Generate factory function
+ fmt.Fprintf(buf, "func NewSerializerFor_%s() fory.Serializer {\n",
s.Name)
+ fmt.Fprintf(buf, "\treturn %s_ForyGenSerializer{}\n", s.Name)
+ fmt.Fprintf(buf, "}\n\n")
+
// Generate TypeId method
fmt.Fprintf(buf, "func (%s_ForyGenSerializer) TypeId() fory.TypeId
{\n", s.Name)
fmt.Fprintf(buf, "\treturn fory.NAMED_STRUCT\n")
@@ -462,10 +467,10 @@ func generateCode(pkg *packages.Package, structs
[]*StructInfo) error {
fmt.Fprintf(&buf, "\t\"github.com/apache/fory/go/fory\"\n")
fmt.Fprintf(&buf, ")\n\n")
- // Generate init function to register serializers
+ // Generate init function to register serializer factories
fmt.Fprintf(&buf, "func init() {\n")
for _, s := range structs {
- fmt.Fprintf(&buf,
"\tfory.RegisterGeneratedSerializer((*%s)(nil), %s_ForyGenSerializer{})\n",
s.Name, s.Name)
+ fmt.Fprintf(&buf, "\tfory.RegisterSerializerFactory((*%s)(nil),
NewSerializerFor_%s)\n", s.Name, s.Name)
}
fmt.Fprintf(&buf, "}\n\n")
diff --git a/go/fory/fory.go b/go/fory/fory.go
index dbc81d584..becca516d 100644
--- a/go/fory/fory.go
+++ b/go/fory/fory.go
@@ -31,31 +31,7 @@ func NewFory(referenceTracking bool) *Fory {
language: XLANG,
buffer: NewByteBuffer(nil),
}
- // Create a new type resolver for this instance but copy generated
serializers from global resolver
- fory.typeResolver = newTypeResolver(fory)
-
- // Copy generated serializers from global resolver to this instance
- if globalTypeResolver != nil {
- for type_, serializer := range
globalTypeResolver.typeToSerializers {
- fory.typeResolver.typeToSerializers[type_] = serializer
- }
- for typeId, type_ := range globalTypeResolver.typeIdToType {
- fory.typeResolver.typeIdToType[typeId] = type_
- }
- }
-
- return fory
-}
-
-// NewForyWithIsolatedTypes creates a Fory instance with isolated type resolver
-// for use cases that need independent type registration
-func NewForyWithIsolatedTypes(referenceTracking bool) *Fory {
- fory := &Fory{
- refResolver: newRefResolver(referenceTracking),
- referenceTracking: referenceTracking,
- language: XLANG,
- buffer: NewByteBuffer(nil),
- }
+ // Create a new type resolver for this instance
fory.typeResolver = newTypeResolver(fory)
return fory
}
diff --git a/go/fory/type.go b/go/fory/type.go
index af30a6dc1..8d1bc68f8 100644
--- a/go/fory/type.go
+++ b/go/fory/type.go
@@ -24,6 +24,7 @@ import (
"regexp"
"strconv"
"strings"
+ "sync"
"time"
"github.com/apache/fory/go/fory/meta"
@@ -225,71 +226,24 @@ var (
genericSetType = reflect.TypeOf((*GenericSet)(nil)).Elem()
)
-// Global type resolver shared by all Fory instances for generated serializers
-var globalTypeResolver *typeResolver
-
-func init() {
- // Initialize global type resolver after other init functions
- initGlobalTypeResolver()
+// Global registry for generated serializer factories
+var generatedSerializerFactories = struct {
+ mu sync.RWMutex
+ factories map[reflect.Type]func() Serializer
+}{
+ factories: make(map[reflect.Type]func() Serializer),
}
-func initGlobalTypeResolver() {
- // Create a dummy fory instance just for initializing the global type
resolver
- r := &typeResolver{
- typeTagToSerializers: map[string]Serializer{},
- typeToSerializers: map[reflect.Type]Serializer{},
- typeIdToType: map[int16]reflect.Type{},
- typeToTypeInfo: map[reflect.Type]string{},
- typeInfoToType: map[string]reflect.Type{},
- dynamicStringToId: map[string]int16{},
- dynamicIdToString: map[int16]string{},
-
- language: XLANG,
- metaStringResolver: NewMetaStringResolver(),
- requireRegistration: false,
-
- metaStrToStr: make(map[string]string),
- metaStrToClass: make(map[string]reflect.Type),
- hashToMetaString: make(map[uint64]string),
- hashToClassInfo: make(map[uint64]TypeInfo),
-
- dynamicWrittenMetaStr: make([]string, 0),
- typeIDToTypeInfo: make(map[int32]TypeInfo),
- typeIDCounter: 300,
- dynamicWriteStringID: 0,
-
- typesInfo: make(map[reflect.Type]TypeInfo),
- nsTypeToTypeInfo: make(map[nsTypeKey]TypeInfo),
- namedTypeToTypeInfo: make(map[namedTypeKey]TypeInfo),
-
- namespaceEncoder: meta.NewEncoder('.', '_'),
- namespaceDecoder: meta.NewDecoder('.', '_'),
- typeNameEncoder: meta.NewEncoder('$', '_'),
- typeNameDecoder: meta.NewDecoder('$', '_'),
+// RegisterSerializerFactory registers a factory function for a generated
serializer
+func RegisterSerializerFactory(type_ interface{}, factory func() Serializer) {
+ reflectType := reflect.TypeOf(type_)
+ if reflectType.Kind() == reflect.Ptr {
+ reflectType = reflectType.Elem()
}
- // Initialize base type mappings - copy from newTypeResolver
- for _, t := range []reflect.Type{
- boolType,
- byteType,
- int8Type,
- int16Type,
- int32Type,
- intType,
- int64Type,
- float32Type,
- float64Type,
- stringType,
- dateType,
- timestampType,
- interfaceType,
- genericSetType,
- } {
- r.typeInfoToType[t.String()] = t
- r.typeToTypeInfo[t] = t.String()
- }
- r.initialize()
- globalTypeResolver = r
+ generatedSerializerFactories.mu.Lock()
+ defer generatedSerializerFactories.mu.Unlock()
+ generatedSerializerFactories.factories[reflectType] = factory
}
type TypeInfo struct {
@@ -410,6 +364,18 @@ func newTypeResolver(fory *Fory) *typeResolver {
r.typeToTypeInfo[t] = t.String()
}
r.initialize()
+
+ // Register generated serializers from factories
+ generatedSerializerFactories.mu.RLock()
+ for type_, factory := range generatedSerializerFactories.factories {
+ serializer := factory()
+ r.typeToSerializers[type_] = serializer
+ if typeId := serializer.TypeId(); typeId >
NotSupportCrossLanguage {
+ r.typeIdToType[typeId] = type_
+ }
+ }
+ generatedSerializerFactories.mu.RUnlock()
+
return r
}
@@ -469,39 +435,6 @@ func (r *typeResolver) RegisterSerializer(type_
reflect.Type, s Serializer) erro
return nil
}
-// RegisterGeneratedSerializer registers a generated serializer for a specific
type.
-// Generated serializers have priority over reflection-based serializers and
can override existing ones.
-func RegisterGeneratedSerializer(type_ interface{}, s Serializer) error {
- if type_ == nil {
- return fmt.Errorf("type_ cannot be nil")
- }
-
- reflectType := reflect.TypeOf(type_)
- if reflectType.Kind() == reflect.Ptr {
- reflectType = reflectType.Elem()
- }
-
- // Use the global type resolver
- if globalTypeResolver == nil {
- return fmt.Errorf("global type resolver not initialized")
- }
-
- // Allow overriding existing serializers by directly setting the map
- // This gives generated serializers priority over reflection-based ones
- globalTypeResolver.typeToSerializers[reflectType] = s
-
- // Handle typeId registration
- typeId := s.TypeId()
- if typeId != FORY_TYPE_TAG {
- if typeId > NotSupportCrossLanguage {
- // Allow overriding existing typeId mappings as well
- globalTypeResolver.typeIdToType[typeId] = reflectType
- }
- }
-
- return nil
-}
-
func (r *typeResolver) RegisterTypeTag(value reflect.Value, tag string) error {
type_ := value.Type()
if prev, ok := r.typeToSerializers[type_]; ok {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]