You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pulsar.apache.org by "gunli (via GitHub)" <gi...@apache.org> on 2023/06/25 04:34:28 UTC

[GitHub] [pulsar-client-go] gunli opened a new pull request, #1033: [Improve] improve the perf of schema and schema cache

gunli opened a new pull request, #1033:
URL: https://github.com/apache/pulsar-client-go/pull/1033

   <!--
   ### Contribution Checklist
     
     - Name the pull request in the form "[Issue XYZ][component] Title of the pull request", where *XYZ* should be replaced by the actual issue number.
       Skip *Issue XYZ* if there is no associated github issue for this pull request.
       Skip *component* if you are unsure about which is the best component. E.g. `[docs] Fix typo in produce method`.
   
     - Fill out the template below to describe the changes contributed by the pull request. That will give reviewers the context they need to do the review.
     
     - Each pull request should address only one issue, not mix up code from multiple issues.
     
     - Each commit in the pull request has a meaningful commit message
   
     - Once all items of the checklist are addressed, remove the above text and this checklist, leaving only the filled out template below.
   
   **(The sections below can be removed for hotfixes of typos)**
   -->
   
   *(If this PR fixes a github issue, please add `Fixes #<xyz>`.)*
   
   Fixes #<xyz>
   
   SchemaInfo.hash() and schemaCache.Get() are frequently called by partitionProducer.internalSend(), current implementation of these functions use sync.RWMutex to sync the cache map and calculate the hash every call, use the sync.Map and cache the hash value can improve the performance.
   
   Master Issue: #<xyz>
   
   ### Motivation
   
   
   *Explain here the context, and why you're making that change. What is the problem you're trying to solve.*
   
   ### Modifications
   
   *Describe the modifications you've done.*
   - Modified: pulsar/producer_partition.go
   - Modified: pulsar/schema.go
   
   ### Verifying this change
   
   - [x] Make sure that the change passes the CI checks.
   
   *(Please pick either of the following options)*
   
   This change is a trivial rework / code cleanup without any test coverage.
   
   *(or)*
   
   This change is already covered by existing tests, such as *(please describe tests)*.
   
   *(or)*
   
   This change added tests and can be verified as follows:
   
   *(example:)*
     - *Added integration tests for end-to-end deployment with large payloads (10MB)*
     - *Extended integration test for recovery after broker failure*
   
   ### Does this pull request potentially affect one of the following parts:
   
   *If `yes` was chosen, please highlight the changes*
   
     - Dependencies (does it add or upgrade a dependency): (no)
     - The public API: (yes / no)
     - **The schema: (yes)**
     - The default values of configurations: (no)
     - The wire protocol: ( no)
   
   ### Documentation
   
     - Does this pull request introduce a new feature? (no)
     - If yes, how is the feature documented? (not applicable / docs / GoDocs / not documented)
     - If a feature is not applicable for documentation, explain why?
     - If a feature is not documented yet in this PR, please create a followup issue for adding the documentation
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pulsar.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [pulsar-client-go] gunli commented on a diff in pull request #1033: [Improve] improve the perf of schema and schema cache

Posted by "gunli (via GitHub)" <gi...@apache.org>.
gunli commented on code in PR #1033:
URL: https://github.com/apache/pulsar-client-go/pull/1033#discussion_r1246561821


##########
pulsar/schema.go:
##########
@@ -37,27 +38,27 @@ import (
 type SchemaType int
 
 const (
-	NONE        SchemaType = iota //No schema defined

Review Comment:
   Hi shibd, I have revert the comment



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pulsar.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [pulsar-client-go] gunli commented on a diff in pull request #1033: [Improve] improve the perf of schema and schema cache

Posted by "gunli (via GitHub)" <gi...@apache.org>.
gunli commented on code in PR #1033:
URL: https://github.com/apache/pulsar-client-go/pull/1033#discussion_r1246535670


##########
pulsar/schema.go:
##########
@@ -66,13 +67,21 @@ type SchemaInfo struct {
 	Schema     string
 	Type       SchemaType
 	Properties map[string]string
+	hashVal    atomic.Uint64
 }
 
-func (s SchemaInfo) hash() uint64 {
+func (s *SchemaInfo) hash() uint64 {
+	oldHash := s.hashVal.Load()
+	if oldHash != 0 {
+		return oldHash
+	}
+
 	h := maphash.Hash{}
 	h.SetSeed(seed)
 	h.Write([]byte(s.Schema))
-	return h.Sum64()
+	newHash := h.Sum64()
+	s.hashVal.CompareAndSwap(oldHash, newHash)

Review Comment:
   I think `atomic` is enough, 'cause in sync.Once, there is an `atomic` and a `mutex`, when we read the hash, it will `atomic.LoadUint32(&o.done)` first, the costs are the same.
   
   ``` go
   type Once struct {
   	// done indicates whether the action has been performed.
   	// It is first in the struct because it is used in the hot path.
   	// The hot path is inlined at every call site.
   	// Placing done first allows more compact instructions on some architectures (amd64/386),
   	// and fewer instructions (to calculate offset) on other architectures.
   	done uint32
   	m    Mutex
   }
   
   func (o *Once) Do(f func()) {
   	// Note: Here is an incorrect implementation of Do:
   	//
   	//	if atomic.CompareAndSwapUint32(&o.done, 0, 1) {
   	//		f()
   	//	}
   	//
   	// Do guarantees that when it returns, f has finished.
   	// This implementation would not implement that guarantee:
   	// given two simultaneous calls, the winner of the cas would
   	// call f, and the second would return immediately, without
   	// waiting for the first's call to f to complete.
   	// This is why the slow path falls back to a mutex, and why
   	// the atomic.StoreUint32 must be delayed until after f returns.
   
   	if atomic.LoadUint32(&o.done) == 0 {
   		// Outlined slow-path to allow inlining of the fast-path.
   		o.doSlow(f)
   	}
   }
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pulsar.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [pulsar-client-go] gunli commented on a diff in pull request #1033: [Improve] improve the perf of schema and schema cache

Posted by "gunli (via GitHub)" <gi...@apache.org>.
gunli commented on code in PR #1033:
URL: https://github.com/apache/pulsar-client-go/pull/1033#discussion_r1247907066


##########
pulsar/schema.go:
##########
@@ -66,13 +67,21 @@ type SchemaInfo struct {
 	Schema     string
 	Type       SchemaType
 	Properties map[string]string
+	hashVal    atomic.Uint64
 }
 
-func (s SchemaInfo) hash() uint64 {
+func (s *SchemaInfo) hash() uint64 {
+	oldHash := s.hashVal.Load()
+	if oldHash != 0 {
+		return oldHash
+	}
+
 	h := maphash.Hash{}
 	h.SetSeed(seed)
 	h.Write([]byte(s.Schema))
-	return h.Sum64()
+	newHash := h.Sum64()
+	s.hashVal.CompareAndSwap(oldHash, newHash)

Review Comment:
   Hi sbibd, I have checked it again, since there is a mutex field in sync.Once, if we use sync.Once, we must add it to SchemaInfo as a pointer, not a value, 'cause copying mutex value is not allowed, so we must init the sync.Once field for all the schemas, such NewAvroSchema, NewStringSchema..., all these functions need to be updated. And, each time we add a new schema type, we must remember to init this pointer, or it will be panic, I think it is not good for maintaining. An atomic.Uint64 is a value, no need to init and has no those problems.
   
   In multi-threaded, race will be stopped when the hashVal is set, the race times is few, I think it is acceptable.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pulsar.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [pulsar-client-go] shibd merged pull request #1033: [Improve] improve the perf of schema and schema cache

Posted by "shibd (via GitHub)" <gi...@apache.org>.
shibd merged PR #1033:
URL: https://github.com/apache/pulsar-client-go/pull/1033


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pulsar.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [pulsar-client-go] shibd commented on a diff in pull request #1033: [Improve] improve the perf of schema and schema cache

Posted by "shibd (via GitHub)" <gi...@apache.org>.
shibd commented on code in PR #1033:
URL: https://github.com/apache/pulsar-client-go/pull/1033#discussion_r1247323891


##########
pulsar/schema.go:
##########
@@ -66,13 +67,21 @@ type SchemaInfo struct {
 	Schema     string
 	Type       SchemaType
 	Properties map[string]string
+	hashVal    atomic.Uint64
 }
 
-func (s SchemaInfo) hash() uint64 {
+func (s *SchemaInfo) hash() uint64 {
+	oldHash := s.hashVal.Load()
+	if oldHash != 0 {
+		return oldHash
+	}
+
 	h := maphash.Hash{}
 	h.SetSeed(seed)
 	h.Write([]byte(s.Schema))
-	return h.Sum64()
+	newHash := h.Sum64()
+	s.hashVal.CompareAndSwap(oldHash, newHash)

Review Comment:
   But, Using `sync.once` is more intuitive.
   
   And, In multi-thread, your implementation of this is not guaranteed to be hashed only once.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pulsar.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [pulsar-client-go] gunli commented on a diff in pull request #1033: [Improve] improve the perf of schema and schema cache

Posted by "gunli (via GitHub)" <gi...@apache.org>.
gunli commented on code in PR #1033:
URL: https://github.com/apache/pulsar-client-go/pull/1033#discussion_r1251597833


##########
pulsar/schema.go:
##########
@@ -66,13 +67,21 @@ type SchemaInfo struct {
 	Schema     string
 	Type       SchemaType
 	Properties map[string]string
+	hashVal    atomic.Uint64
 }
 
-func (s SchemaInfo) hash() uint64 {
+func (s *SchemaInfo) hash() uint64 {
+	oldHash := s.hashVal.Load()
+	if oldHash != 0 {
+		return oldHash
+	}
+
 	h := maphash.Hash{}
 	h.SetSeed(seed)
 	h.Write([]byte(s.Schema))
-	return h.Sum64()
+	newHash := h.Sum64()
+	s.hashVal.CompareAndSwap(oldHash, newHash)

Review Comment:
   @shibd I have update to sync.Once since there is no atomic.Uint64 in go 1.18



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pulsar.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [pulsar-client-go] gunli commented on a diff in pull request #1033: [Improve] improve the perf of schema and schema cache

Posted by "gunli (via GitHub)" <gi...@apache.org>.
gunli commented on code in PR #1033:
URL: https://github.com/apache/pulsar-client-go/pull/1033#discussion_r1247907066


##########
pulsar/schema.go:
##########
@@ -66,13 +67,21 @@ type SchemaInfo struct {
 	Schema     string
 	Type       SchemaType
 	Properties map[string]string
+	hashVal    atomic.Uint64
 }
 
-func (s SchemaInfo) hash() uint64 {
+func (s *SchemaInfo) hash() uint64 {
+	oldHash := s.hashVal.Load()
+	if oldHash != 0 {
+		return oldHash
+	}
+
 	h := maphash.Hash{}
 	h.SetSeed(seed)
 	h.Write([]byte(s.Schema))
-	return h.Sum64()
+	newHash := h.Sum64()
+	s.hashVal.CompareAndSwap(oldHash, newHash)

Review Comment:
   Hi sbibd, I have checked it again, since there is a mutex field in sync.Once, if we use sync.Once, we must add it to SchemaInfo as a pointer, not a value, 'cause copying mutex value is not allowed, so we must init the sync.Once field for all the schemas, such NewAvroSchema, NewStringSchema..., each time we add a new schema type, we must remember to init this pointer, or it will be panic, I think it not good for maintaining.
   
   In multi-threaded, race will be stopped when the hashVal is set, the race time is few, I think it is acceptable.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pulsar.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [pulsar-client-go] gunli commented on a diff in pull request #1033: [Improve] improve the perf of schema and schema cache

Posted by "gunli (via GitHub)" <gi...@apache.org>.
gunli commented on code in PR #1033:
URL: https://github.com/apache/pulsar-client-go/pull/1033#discussion_r1246524572


##########
pulsar/schema.go:
##########
@@ -37,27 +38,27 @@ import (
 type SchemaType int
 
 const (
-	NONE        SchemaType = iota //No schema defined

Review Comment:
   OK, but I think it is better to keep a same comment format for a project, so I configured my IDE to run gofmt when I save the files, I have to update my IDE config when I prepare a PR, and revert the config when I do my own job, it not so convinient...



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pulsar.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [pulsar-client-go] shibd commented on a diff in pull request #1033: [Improve] improve the perf of schema and schema cache

Posted by "shibd (via GitHub)" <gi...@apache.org>.
shibd commented on code in PR #1033:
URL: https://github.com/apache/pulsar-client-go/pull/1033#discussion_r1247324476


##########
pulsar/schema.go:
##########
@@ -37,27 +38,27 @@ import (
 type SchemaType int
 
 const (
-	NONE        SchemaType = iota //No schema defined

Review Comment:
   Yes, If there is a good way to automate, you can contribute to the code format alone,



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pulsar.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [pulsar-client-go] gunli commented on a diff in pull request #1033: [Improve] improve the perf of schema and schema cache

Posted by "gunli (via GitHub)" <gi...@apache.org>.
gunli commented on code in PR #1033:
URL: https://github.com/apache/pulsar-client-go/pull/1033#discussion_r1246525173


##########
pulsar/schema.go:
##########
@@ -66,13 +67,21 @@ type SchemaInfo struct {
 	Schema     string
 	Type       SchemaType
 	Properties map[string]string
+	hashVal    atomic.Uint64
 }
 
-func (s SchemaInfo) hash() uint64 {
+func (s *SchemaInfo) hash() uint64 {
+	oldHash := s.hashVal.Load()
+	if oldHash != 0 {
+		return oldHash
+	}
+
 	h := maphash.Hash{}
 	h.SetSeed(seed)
 	h.Write([]byte(s.Schema))
-	return h.Sum64()
+	newHash := h.Sum64()
+	s.hashVal.CompareAndSwap(oldHash, newHash)

Review Comment:
   OK, Let me have a look.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pulsar.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [pulsar-client-go] shibd commented on a diff in pull request #1033: [Improve] improve the perf of schema and schema cache

Posted by "shibd (via GitHub)" <gi...@apache.org>.
shibd commented on code in PR #1033:
URL: https://github.com/apache/pulsar-client-go/pull/1033#discussion_r1246387681


##########
pulsar/schema.go:
##########
@@ -66,13 +67,21 @@ type SchemaInfo struct {
 	Schema     string
 	Type       SchemaType
 	Properties map[string]string
+	hashVal    atomic.Uint64
 }
 
-func (s SchemaInfo) hash() uint64 {
+func (s *SchemaInfo) hash() uint64 {
+	oldHash := s.hashVal.Load()
+	if oldHash != 0 {
+		return oldHash
+	}
+
 	h := maphash.Hash{}
 	h.SetSeed(seed)
 	h.Write([]byte(s.Schema))
-	return h.Sum64()
+	newHash := h.Sum64()
+	s.hashVal.CompareAndSwap(oldHash, newHash)

Review Comment:
   We can use `sync.Once` to ensure `hashVal` just set value on first call time.
   
   ``` go
   	s.onc.Do(func() {
   		h := maphash.Hash{}
   		h.SetSeed(seed)
   		h.Write([]byte(s.Schema))
   		s.hashVal = h.Sum64()
   	})
   	return s.hashVal
   ```



##########
pulsar/schema.go:
##########
@@ -37,27 +38,27 @@ import (
 type SchemaType int
 
 const (
-	NONE        SchemaType = iota //No schema defined

Review Comment:
   Please do not submit format changes that are not related to this PR.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pulsar.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [pulsar-client-go] gunli commented on a diff in pull request #1033: [Improve] improve the perf of schema and schema cache

Posted by "gunli (via GitHub)" <gi...@apache.org>.
gunli commented on code in PR #1033:
URL: https://github.com/apache/pulsar-client-go/pull/1033#discussion_r1247907066


##########
pulsar/schema.go:
##########
@@ -66,13 +67,21 @@ type SchemaInfo struct {
 	Schema     string
 	Type       SchemaType
 	Properties map[string]string
+	hashVal    atomic.Uint64
 }
 
-func (s SchemaInfo) hash() uint64 {
+func (s *SchemaInfo) hash() uint64 {
+	oldHash := s.hashVal.Load()
+	if oldHash != 0 {
+		return oldHash
+	}
+
 	h := maphash.Hash{}
 	h.SetSeed(seed)
 	h.Write([]byte(s.Schema))
-	return h.Sum64()
+	newHash := h.Sum64()
+	s.hashVal.CompareAndSwap(oldHash, newHash)

Review Comment:
   Hi sbibd, I have checked it again, since there is a mutex field in sync.Once, if we use sync.Once, we must add it to SchemaInfo as a pointer, not a value, 'cause copying mutex value is not allowed, so we must init the sync.Once field for all the schemas, such NewAvroSchema, NewStringSchema..., all these functions need to be updated. And, each time we add a new schema type, we must remember to init this pointer, or it will be panic, I think it not good for maintaining.
   
   In multi-threaded, race will be stopped when the hashVal is set, the race time is few, I think it is acceptable.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@pulsar.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org