From 9be92cc3d489f7c14544d59a91c26f824a22179d Mon Sep 17 00:00:00 2001 From: jroam Date: Wed, 28 Jul 2021 22:18:06 +0800 Subject: [PATCH 01/11] =?UTF-8?q?garray=E4=BB=A3=E7=A0=81=E8=A7=84?= =?UTF-8?q?=E8=8C=83=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- container/garray/garray_normal_any.go | 4 ++-- container/garray/garray_normal_int.go | 7 ++----- container/garray/garray_normal_str.go | 7 ++----- container/garray/garray_sorted_any.go | 2 +- 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/container/garray/garray_normal_any.go b/container/garray/garray_normal_any.go index a87cb8b41..863274e07 100644 --- a/container/garray/garray_normal_any.go +++ b/container/garray/garray_normal_any.go @@ -36,7 +36,7 @@ func New(safe ...bool) *Array { return NewArraySize(0, 0, safe...) } -// See New. +// NewArray See New. func NewArray(safe ...bool) *Array { return NewArraySize(0, 0, safe...) } @@ -422,7 +422,7 @@ func (a *Array) SubSlice(offset int, length ...int) []interface{} { } } -// See PushRight. +// Append See PushRight. func (a *Array) Append(value ...interface{}) *Array { a.PushRight(value...) return a diff --git a/container/garray/garray_normal_int.go b/container/garray/garray_normal_int.go index c58020eb2..cc04a256a 100644 --- a/container/garray/garray_normal_int.go +++ b/container/garray/garray_normal_int.go @@ -149,10 +149,7 @@ func (a *IntArray) Sort(reverse ...bool) *IntArray { defer a.mu.Unlock() if len(reverse) > 0 && reverse[0] { sort.Slice(a.array, func(i, j int) bool { - if a.array[i] < a.array[j] { - return false - } - return true + return a.array[i] > a.array[j] }) } else { sort.Ints(a.array) @@ -427,7 +424,7 @@ func (a *IntArray) SubSlice(offset int, length ...int) []int { } } -// See PushRight. +// Append See PushRight. func (a *IntArray) Append(value ...int) *IntArray { a.mu.Lock() a.array = append(a.array, value...) diff --git a/container/garray/garray_normal_str.go b/container/garray/garray_normal_str.go index be23bba9d..8f2cb1d83 100644 --- a/container/garray/garray_normal_str.go +++ b/container/garray/garray_normal_str.go @@ -136,10 +136,7 @@ func (a *StrArray) Sort(reverse ...bool) *StrArray { defer a.mu.Unlock() if len(reverse) > 0 && reverse[0] { sort.Slice(a.array, func(i, j int) bool { - if strings.Compare(a.array[i], a.array[j]) < 0 { - return false - } - return true + return strings.Compare(a.array[i], a.array[j]) >= 0 }) } else { sort.Strings(a.array) @@ -414,7 +411,7 @@ func (a *StrArray) SubSlice(offset int, length ...int) []string { } } -// See PushRight. +// Append See PushRight. func (a *StrArray) Append(value ...string) *StrArray { a.mu.Lock() a.array = append(a.array, value...) diff --git a/container/garray/garray_sorted_any.go b/container/garray/garray_sorted_any.go index cd14d6252..780204857 100644 --- a/container/garray/garray_sorted_any.go +++ b/container/garray/garray_sorted_any.go @@ -453,7 +453,7 @@ func (a *SortedArray) binSearch(value interface{}, lock bool) (index int, result mid := 0 cmp := -2 for min <= max { - mid = min + int((max-min)/2) + mid = min + (max-min)/2 cmp = a.getComparator()(value, a.array[mid]) switch { case cmp < 0: From 248e6ff1344ffea94a1fdef80150c65454b63db3 Mon Sep 17 00:00:00 2001 From: jroam Date: Sun, 1 Aug 2021 15:19:48 +0800 Subject: [PATCH 02/11] bugfix garray Sort --- container/garray/garray_normal_int.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/container/garray/garray_normal_int.go b/container/garray/garray_normal_int.go index cc04a256a..83c2624d5 100644 --- a/container/garray/garray_normal_int.go +++ b/container/garray/garray_normal_int.go @@ -149,7 +149,7 @@ func (a *IntArray) Sort(reverse ...bool) *IntArray { defer a.mu.Unlock() if len(reverse) > 0 && reverse[0] { sort.Slice(a.array, func(i, j int) bool { - return a.array[i] > a.array[j] + return a.array[i] >= a.array[j] }) } else { sort.Ints(a.array) From 4c54b1cfbc9fd97d356629a5238486fd64464f94 Mon Sep 17 00:00:00 2001 From: John Guo Date: Wed, 4 Aug 2021 20:50:45 +0800 Subject: [PATCH 03/11] improve errcode feature for package gerror --- errors/gerror/gerror.go | 22 ++++- errors/gerror/gerror_code.go | 84 ++++++++++++------- errors/gerror/gerror_error.go | 5 +- errors/gerror/gerror_z_unit_test.go | 37 +++++++- .../ghttp_middleware_handler_response.go | 6 +- net/ghttp/ghttp_response_write.go | 2 +- ...ghttp_unit_router_handler_extended_test.go | 2 +- util/gconv/gconv.go | 6 +- 8 files changed, 122 insertions(+), 42 deletions(-) diff --git a/errors/gerror/gerror.go b/errors/gerror/gerror.go index b961be831..29e14bb14 100644 --- a/errors/gerror/gerror.go +++ b/errors/gerror/gerror.go @@ -142,10 +142,14 @@ func WrapSkipf(skip int, err error, format string, args ...interface{}) error { } // NewCode creates and returns an error that has error code and given text. -func NewCode(code int, text string) error { +func NewCode(code int, text ...string) error { + errText := "" + if len(text) > 0 { + errText = text[0] + } return &Error{ stack: callers(), - text: text, + text: errText, code: code, } } @@ -238,14 +242,24 @@ func WrapCodeSkipf(code, skip int, err error, format string, args ...interface{} } // Code returns the error code of current error. -// It returns -1 if it has no error code or it does not implements interface Code. +// It returns CodeNil if it has no error code or it does not implements interface Code. func Code(err error) int { if err != nil { if e, ok := err.(apiCode); ok { return e.Code() } } - return -1 + return CodeNil +} + +// CodeMessage retrieves and returns the error code message from given error. +func CodeMessage(err error) string { + return Message(Code(err)) +} + +// Message returns the message string for specified code. +func Message(code int) string { + return codeMessageMap[code] } // Cause returns the root cause error of . diff --git a/errors/gerror/gerror_code.go b/errors/gerror/gerror_code.go index 055ea0ab0..c0eecc0f4 100644 --- a/errors/gerror/gerror_code.go +++ b/errors/gerror/gerror_code.go @@ -9,32 +9,60 @@ package gerror // Reserved internal error code of framework: code < 1000. const ( - // =============================================================================== - // Common system codes. - // =============================================================================== - - CodeNil = -1 // No error code specified. - CodeOk = 0 // It is OK. - CodeInternalError = 50 + iota // An error occurred internally. - CodeValidationFailed // Data validation failed. - CodeDbOperationError // Database operation error. - CodeInvalidParameter // The given parameter for current operation is invalid. - CodeMissingParameter // Parameter for current operation is missing. - CodeInvalidOperation // The function cannot be used like this. - CodeInvalidConfiguration // The configuration is invalid for current operation. - CodeMissingConfiguration // The configuration is missing for current operation. - CodeNotImplemented // The operation is not implemented yet. - CodeNotSupported // The operation is not supported yet. - CodeOperationFailed // I tried, but I cannot give you what you want. - CodeNotAuthorized // Not Authorized. - CodeSecurityReason // Security Reason. - CodeServerBusy // Server is busy, please try again later. - CodeUnknown // Unknown error. - CodeResourceNotExist // Resource does not exist. - - // =============================================================================== - // Common business codes. - // =============================================================================== - - CodeBusinessValidationFailed = 300 + iota // Business validation failed. + CodeNil = -1 // No error code specified. + CodeOk = 0 // It is OK. + CodeInternalError = 50 // An error occurred internally. + CodeValidationFailed = 51 // Data validation failed. + CodeDbOperationError = 52 // Database operation error. + CodeInvalidParameter = 53 // The given parameter for current operation is invalid. + CodeMissingParameter = 54 // Parameter for current operation is missing. + CodeInvalidOperation = 55 // The function cannot be used like this. + CodeInvalidConfiguration = 56 // The configuration is invalid for current operation. + CodeMissingConfiguration = 57 // The configuration is missing for current operation. + CodeNotImplemented = 58 // The operation is not implemented yet. + CodeNotSupported = 59 // The operation is not supported yet. + CodeOperationFailed = 60 // I tried, but I cannot give you what you want. + CodeNotAuthorized = 61 // Not Authorized. + CodeSecurityReason = 62 // Security Reason. + CodeServerBusy = 63 // Server is busy, please try again later. + CodeUnknown = 64 // Unknown error. + CodeResourceNotExist = 65 // Resource does not exist. + CodeBusinessValidationFailed = 300 // Business validation failed. ) + +var ( + // codeMessageMap is the mapping from code to according string message. + codeMessageMap = map[int]string{ + CodeNil: "", + CodeOk: "OK", + CodeInternalError: "Internal Error", + CodeValidationFailed: "Validation Failed", + CodeDbOperationError: "Database Operation Error", + CodeInvalidParameter: "Invalid Parameter", + CodeMissingParameter: "Missing Parameter", + CodeInvalidOperation: "Invalid Operation", + CodeInvalidConfiguration: "Invalid Configuration", + CodeMissingConfiguration: "Missing Configuration", + CodeNotImplemented: "Not Implemented", + CodeNotSupported: "Not Supported", + CodeOperationFailed: "Operation Failed", + CodeNotAuthorized: "Not Authorized", + CodeSecurityReason: "Security Reason", + CodeServerBusy: "Server Is Busy", + CodeUnknown: "Unknown Error", + CodeResourceNotExist: "Resource Not Exist", + CodeBusinessValidationFailed: "Business Validation Failed", + } +) + +// RegisterCode registers custom error code to global error codes for gerror recognition. +func RegisterCode(code int, message string) { + codeMessageMap[code] = message +} + +// RegisterCodeMap registers custom error codes to global error codes for gerror recognition using map. +func RegisterCodeMap(codes map[int]string) { + for k, v := range codes { + codeMessageMap[k] = v + } +} diff --git a/errors/gerror/gerror_error.go b/errors/gerror/gerror_error.go index 045385d84..f0953f7ce 100644 --- a/errors/gerror/gerror_error.go +++ b/errors/gerror/gerror_error.go @@ -57,10 +57,10 @@ func (err *Error) Error() string { } // Code returns the error code. -// It returns -1 if it has no error code. +// It returns CodeNil if it has no error code. func (err *Error) Code() int { if err == nil { - return -1 + return CodeNil } return err.code } @@ -159,6 +159,7 @@ func (err *Error) Current() error { error: nil, stack: err.stack, text: err.text, + code: err.code, } } diff --git a/errors/gerror/gerror_z_unit_test.go b/errors/gerror/gerror_z_unit_test.go index e60243aa7..0bffed596 100644 --- a/errors/gerror/gerror_z_unit_test.go +++ b/errors/gerror/gerror_z_unit_test.go @@ -261,8 +261,8 @@ func Test_Code(t *testing.T) { t.Assert(err.Error(), "123") }) gtest.C(t, func(t *gtest.T) { - err := gerror.NewCode(1, "123") - t.Assert(gerror.Code(err), 1) + err := gerror.NewCode(gerror.CodeUnknown, "123") + t.Assert(gerror.Code(err), gerror.CodeUnknown) t.Assert(err.Error(), "123") }) gtest.C(t, func(t *gtest.T) { @@ -318,3 +318,36 @@ func Test_Json(t *testing.T) { t.Assert(string(b), `"2: 1"`) }) } + +func Test_Message(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + t.Assert(gerror.Message(-100), ``) + t.Assert(gerror.Message(gerror.CodeNil), ``) + t.Assert(gerror.Message(gerror.CodeOk), `OK`) + }) +} + +func Test_CodeMessage(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + err := gerror.NewCode(gerror.CodeUnknown) + t.Assert(gerror.CodeMessage(err), `Unknown Error`) + }) +} + +func Test_RegisterCode(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + gerror.RegisterCode(10086, "MobileTelecom") + t.Assert(gerror.Message(10086), `MobileTelecom`) + }) +} + +func Test_RegisterCodeMap(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + gerror.RegisterCodeMap(map[int]string{ + 10087: "MobileTelecom 10087", + 10088: "MobileTelecom 10088", + }) + t.Assert(gerror.Message(10087), `MobileTelecom 10087`) + t.Assert(gerror.Message(10088), `MobileTelecom 10088`) + }) +} diff --git a/net/ghttp/ghttp_middleware_handler_response.go b/net/ghttp/ghttp_middleware_handler_response.go index f8c71c318..892ac796b 100644 --- a/net/ghttp/ghttp_middleware_handler_response.go +++ b/net/ghttp/ghttp_middleware_handler_response.go @@ -31,9 +31,13 @@ func MiddlewareHandlerResponse(r *Request) { if code == gerror.CodeNil { code = gerror.CodeInternalError } + message := err.Error() + if message == "" { + message = gerror.Message(code) + } internalErr = r.Response.WriteJson(DefaultHandlerResponse{ Code: code, - Message: err.Error(), + Message: message, Data: nil, }) if internalErr != nil { diff --git a/net/ghttp/ghttp_response_write.go b/net/ghttp/ghttp_response_write.go index f8aca67a6..c7dbd10f8 100644 --- a/net/ghttp/ghttp_response_write.go +++ b/net/ghttp/ghttp_response_write.go @@ -71,7 +71,7 @@ func (r *Response) WritefExit(format string, params ...interface{}) { r.Request.Exit() } -// Writef writes the response with and new line. +// Writeln writes the response with and new line. func (r *Response) Writeln(content ...interface{}) { if len(content) == 0 { r.Write("\n") diff --git a/net/ghttp/ghttp_unit_router_handler_extended_test.go b/net/ghttp/ghttp_unit_router_handler_extended_test.go index 49f00095c..77d50c8f2 100644 --- a/net/ghttp/ghttp_unit_router_handler_extended_test.go +++ b/net/ghttp/ghttp_unit_router_handler_extended_test.go @@ -77,6 +77,6 @@ func Test_Router_Handler_Extended_Handler_WithObject(t *testing.T) { client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p)) t.Assert(client.GetContent("/test?age=18&name=john"), `{"code":0,"message":"","data":{"Id":1,"Age":18,"Name":"john"}}`) - t.Assert(client.GetContent("/test/error"), `{"code":52,"message":"error","data":null}`) + t.Assert(client.GetContent("/test/error"), `{"code":50,"message":"error","data":null}`) }) } diff --git a/util/gconv/gconv.go b/util/gconv/gconv.go index 77e492fe8..0a72171f8 100644 --- a/util/gconv/gconv.go +++ b/util/gconv/gconv.go @@ -53,7 +53,7 @@ type doConvertInput struct { Extra []interface{} // Extra values for implementing the converting. } -// doConvert does common used types converting. +// doConvert does commonly used types converting. func doConvert(input doConvertInput) interface{} { switch input.ToTypeName { case "int": @@ -366,7 +366,7 @@ func Runes(any interface{}) []rune { } // String converts `any` to string. -// It's most common used converting function. +// It's most commonly used converting function. func String(any interface{}) string { if any == nil { return "" @@ -459,7 +459,7 @@ func String(any interface{}) string { if kind == reflect.Ptr { return String(rv.Elem().Interface()) } - // Finally we use json.Marshal to convert. + // Finally, we use json.Marshal to convert. if jsonContent, err := json.Marshal(value); err != nil { return fmt.Sprint(value) } else { From 537cbf983e9a0e7ebfd0d7ea29850dc8f0c4e351 Mon Sep 17 00:00:00 2001 From: jroam Date: Wed, 4 Aug 2021 23:35:29 +0800 Subject: [PATCH 04/11] edit some function annotations --- container/garray/garray_normal_any.go | 4 ++-- container/garray/garray_normal_int.go | 2 +- container/garray/garray_normal_str.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/container/garray/garray_normal_any.go b/container/garray/garray_normal_any.go index 863274e07..0e16736de 100644 --- a/container/garray/garray_normal_any.go +++ b/container/garray/garray_normal_any.go @@ -36,7 +36,7 @@ func New(safe ...bool) *Array { return NewArraySize(0, 0, safe...) } -// NewArray See New. +// NewArray is alias of New, please see New. func NewArray(safe ...bool) *Array { return NewArraySize(0, 0, safe...) } @@ -422,7 +422,7 @@ func (a *Array) SubSlice(offset int, length ...int) []interface{} { } } -// Append See PushRight. +// Append is alias of PushRight, please See PushRight. func (a *Array) Append(value ...interface{}) *Array { a.PushRight(value...) return a diff --git a/container/garray/garray_normal_int.go b/container/garray/garray_normal_int.go index 83c2624d5..44e577383 100644 --- a/container/garray/garray_normal_int.go +++ b/container/garray/garray_normal_int.go @@ -424,7 +424,7 @@ func (a *IntArray) SubSlice(offset int, length ...int) []int { } } -// Append See PushRight. +// Append is alias of PushRight,please See PushRight. func (a *IntArray) Append(value ...int) *IntArray { a.mu.Lock() a.array = append(a.array, value...) diff --git a/container/garray/garray_normal_str.go b/container/garray/garray_normal_str.go index 8f2cb1d83..61fd0e8d0 100644 --- a/container/garray/garray_normal_str.go +++ b/container/garray/garray_normal_str.go @@ -411,7 +411,7 @@ func (a *StrArray) SubSlice(offset int, length ...int) []string { } } -// Append See PushRight. +// Append is alias of PushRight,please See PushRight. func (a *StrArray) Append(value ...string) *StrArray { a.mu.Lock() a.array = append(a.array, value...) From 00d7ee93b240f541e28bd173a0a2b577b8e1c74e Mon Sep 17 00:00:00 2001 From: John Guo Date: Thu, 5 Aug 2021 11:40:31 +0800 Subject: [PATCH 05/11] improve package gerror --- errors/gerror/gerror_error.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/errors/gerror/gerror_error.go b/errors/gerror/gerror_error.go index f0953f7ce..0c15b0410 100644 --- a/errors/gerror/gerror_error.go +++ b/errors/gerror/gerror_error.go @@ -47,6 +47,9 @@ func (err *Error) Error() string { return "" } errStr := err.text + if errStr == "" { + errStr = Message(err.code) + } if err.error != nil { if err.text != "" { errStr += ": " From 75ca8669913b86e97575ffa3b2ea14a4dcfffa6c Mon Sep 17 00:00:00 2001 From: John Guo Date: Thu, 5 Aug 2021 19:15:18 +0800 Subject: [PATCH 06/11] fix issue in ghttp.Server --- .../ghttp_middleware_handler_response.go | 6 +----- net/ghttp/ghttp_request_middleware.go | 20 +++++++++---------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/net/ghttp/ghttp_middleware_handler_response.go b/net/ghttp/ghttp_middleware_handler_response.go index 892ac796b..f8c71c318 100644 --- a/net/ghttp/ghttp_middleware_handler_response.go +++ b/net/ghttp/ghttp_middleware_handler_response.go @@ -31,13 +31,9 @@ func MiddlewareHandlerResponse(r *Request) { if code == gerror.CodeNil { code = gerror.CodeInternalError } - message := err.Error() - if message == "" { - message = gerror.Message(code) - } internalErr = r.Response.WriteJson(DefaultHandlerResponse{ Code: code, - Message: message, + Message: err.Error(), Data: nil, }) if internalErr != nil { diff --git a/net/ghttp/ghttp_request_middleware.go b/net/ghttp/ghttp_request_middleware.go index ff8c5a539..8554b4f3f 100644 --- a/net/ghttp/ghttp_request_middleware.go +++ b/net/ghttp/ghttp_request_middleware.go @@ -133,33 +133,33 @@ func (m *middleware) callHandlerFunc(funcInfo handlerFuncInfo) { } if funcInfo.Type.NumIn() == 2 { var ( - request reflect.Value + inputObject reflect.Value ) if funcInfo.Type.In(1).Kind() == reflect.Ptr { - request = reflect.New(funcInfo.Type.In(1).Elem()) - m.request.handlerResponse.Error = m.request.Parse(request.Interface()) + inputObject = reflect.New(funcInfo.Type.In(1).Elem()) + m.request.handlerResponse.Error = m.request.Parse(inputObject.Interface()) } else { - request = reflect.New(funcInfo.Type.In(1).Elem()).Elem() - m.request.handlerResponse.Error = m.request.Parse(request.Addr().Interface()) + inputObject = reflect.New(funcInfo.Type.In(1).Elem()).Elem() + m.request.handlerResponse.Error = m.request.Parse(inputObject.Addr().Interface()) } if m.request.handlerResponse.Error != nil { return } - inputValues = append(inputValues, request) + inputValues = append(inputValues, inputObject) } // Call handler with dynamic created parameter values. results := funcInfo.Value.Call(inputValues) switch len(results) { case 1: - m.request.handlerResponse.Error = results[0].Interface().(error) + if !results[0].IsNil() { + m.request.handlerResponse.Error = results[0].Interface().(error) + } case 2: m.request.handlerResponse.Object = results[0].Interface() if !results[1].IsNil() { - if v := results[1].Interface(); v != nil { - m.request.handlerResponse.Error = v.(error) - } + m.request.handlerResponse.Error = results[1].Interface().(error) } } } From 0e158903c26498cfb0435cedb70bb70652045683 Mon Sep 17 00:00:00 2001 From: John Guo Date: Fri, 6 Aug 2021 12:08:49 +0800 Subject: [PATCH 07/11] improve package gtimer for priority checks --- container/garray/garray_sorted_any.go | 4 +- container/garray/garray_z_bench_any_test.go | 39 ++++++++++++ frame/gins/gins_database.go | 2 +- os/gtime/gtime.go | 1 + os/gtime/gtime_time_zone.go | 1 + os/gtimer/gtimer_entry.go | 4 +- os/gtimer/gtimer_queue.go | 59 ++++++------------- os/gtimer/gtimer_queue_heap.go | 1 + os/gtimer/gtimer_timer_loop.go | 9 ++- .../gtimer_z_unit_timer_internal_test.go | 16 +++++ 10 files changed, 85 insertions(+), 51 deletions(-) create mode 100644 container/garray/garray_z_bench_any_test.go diff --git a/container/garray/garray_sorted_any.go b/container/garray/garray_sorted_any.go index 780204857..f120809a5 100644 --- a/container/garray/garray_sorted_any.go +++ b/container/garray/garray_sorted_any.go @@ -156,9 +156,7 @@ func (a *SortedArray) Append(values ...interface{}) *SortedArray { if cmp > 0 { index++ } - rear := append([]interface{}{}, a.array[index:]...) - a.array = append(a.array[0:index], value) - a.array = append(a.array, rear...) + a.array = append(a.array[:index], append([]interface{}{value}, a.array[index:]...)...) } return a } diff --git a/container/garray/garray_z_bench_any_test.go b/container/garray/garray_z_bench_any_test.go new file mode 100644 index 000000000..477c18a19 --- /dev/null +++ b/container/garray/garray_z_bench_any_test.go @@ -0,0 +1,39 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package garray_test + +import ( + "github.com/gogf/gf/container/garray" + "testing" +) + +type anySortedArrayItem struct { + priority int64 + value interface{} +} + +var ( + anyArray = garray.NewArray() + anySortedArray = garray.NewSortedArray(func(a, b interface{}) int { + return int(a.(anySortedArrayItem).priority - b.(anySortedArrayItem).priority) + }) +) + +func Benchmark_AnyArray_Add(b *testing.B) { + for i := 0; i < b.N; i++ { + anyArray.Append(i) + } +} + +func Benchmark_AnySortedArray_Add(b *testing.B) { + for i := 0; i < b.N; i++ { + anySortedArray.Add(anySortedArrayItem{ + priority: int64(i), + value: i, + }) + } +} diff --git a/frame/gins/gins_database.go b/frame/gins/gins_database.go index ec854722e..dc49a18a6 100644 --- a/frame/gins/gins_database.go +++ b/frame/gins/gins_database.go @@ -139,7 +139,7 @@ func Database(name ...string) gdb.DB { } return db } else { - // It panics often because it dose not find its configuration for given group. + // If panics, often because it does not find its configuration for given group. panic(err) } return nil diff --git a/os/gtime/gtime.go b/os/gtime/gtime.go index fe537fb4c..3cb587369 100644 --- a/os/gtime/gtime.go +++ b/os/gtime/gtime.go @@ -24,6 +24,7 @@ import ( const ( // Short writes for common usage durations. + D = 24 * time.Hour H = time.Hour M = time.Minute diff --git a/os/gtime/gtime_time_zone.go b/os/gtime/gtime_time_zone.go index d7a50eb2c..8b828bee8 100644 --- a/os/gtime/gtime_time_zone.go +++ b/os/gtime/gtime_time_zone.go @@ -15,6 +15,7 @@ var ( // locationMap is time zone name to its location object. // Time zone name is like: Asia/Shanghai. locationMap = make(map[string]*time.Location) + // locationMu is used for concurrent safety for `locationMap`. locationMu = sync.RWMutex{} ) diff --git a/os/gtimer/gtimer_entry.go b/os/gtimer/gtimer_entry.go index beebf21a6..65aac5e3d 100644 --- a/os/gtimer/gtimer_entry.go +++ b/os/gtimer/gtimer_entry.go @@ -33,12 +33,12 @@ func (entry *Entry) Status() int { // Run runs the timer job asynchronously. func (entry *Entry) Run() { leftRunningTimes := entry.times.Add(-1) - // Running times exceeding checks. + // It checks its running times exceeding. if leftRunningTimes < 0 { entry.status.Set(StatusClosed) return } - // This means it does not limit the running times. + // This means it has no limit in running times. if leftRunningTimes == math.MaxInt32-1 { entry.times.Set(math.MaxInt32) } diff --git a/os/gtimer/gtimer_queue.go b/os/gtimer/gtimer_queue.go index 9fb6af73d..54443bdf9 100644 --- a/os/gtimer/gtimer_queue.go +++ b/os/gtimer/gtimer_queue.go @@ -18,9 +18,9 @@ import ( // high priority is served before an element with low priority. // priorityQueue is based on heap structure. type priorityQueue struct { - mu sync.RWMutex - heap *priorityQueueHeap // the underlying queue items manager using heap. - latestPriority *gtype.Int64 // latestPriority stores the most priority value of the heap, which is used to check if necessary to call the Pop of heap by Timer. + mu sync.Mutex + heap *priorityQueueHeap // the underlying queue items manager using heap. + nextPriority *gtype.Int64 // nextPriority stores the next priority value of the heap, which is used to check if necessary to call the Pop of heap by Timer. } // priorityQueueHeap is a heap manager, of which the underlying `array` is a array implementing a heap structure. @@ -37,25 +37,16 @@ type priorityQueueItem struct { // newPriorityQueue creates and returns a priority queue. func newPriorityQueue() *priorityQueue { queue := &priorityQueue{ - heap: &priorityQueueHeap{ - array: make([]priorityQueueItem, 0), - }, - latestPriority: gtype.NewInt64(math.MaxInt64), + heap: &priorityQueueHeap{array: make([]priorityQueueItem, 0)}, + nextPriority: gtype.NewInt64(math.MaxInt64), } heap.Init(queue.heap) return queue } -// Len retrieves and returns the length of the queue. -func (q *priorityQueue) Len() int { - q.mu.RLock() - defer q.mu.RUnlock() - return q.heap.Len() -} - -// LatestPriority retrieves and returns the minimum and the most priority value of the queue. -func (q *priorityQueue) LatestPriority() int64 { - return q.latestPriority.Val() +// NextPriority retrieves and returns the minimum and the most priority value of the queue. +func (q *priorityQueue) NextPriority() int64 { + return q.nextPriority.Val() } // Push pushes a value to the queue. @@ -63,42 +54,30 @@ func (q *priorityQueue) LatestPriority() int64 { // The lesser the `priority` value the higher priority of the `value`. func (q *priorityQueue) Push(value interface{}, priority int64) { q.mu.Lock() + defer q.mu.Unlock() heap.Push(q.heap, priorityQueueItem{ value: value, priority: priority, }) - q.mu.Unlock() // Update the minimum priority using atomic operation. - for { - latestPriority := q.latestPriority.Val() - if priority >= latestPriority { - break - } - if q.latestPriority.Cas(latestPriority, priority) { - break - } + nextPriority := q.nextPriority.Val() + if priority >= nextPriority { + return } + q.nextPriority.Set(priority) } // Pop retrieves, removes and returns the most high priority value from the queue. func (q *priorityQueue) Pop() interface{} { q.mu.Lock() + defer q.mu.Unlock() if v := heap.Pop(q.heap); v != nil { - item := v.(priorityQueueItem) - q.mu.Unlock() - // Update the minimum priority using atomic operation. - for { - latestPriority := q.latestPriority.Val() - if item.priority >= latestPriority { - break - } - if q.latestPriority.Cas(latestPriority, item.priority) { - break - } + var nextPriority int64 = math.MaxInt64 + if len(q.heap.array) > 0 { + nextPriority = q.heap.array[0].priority } - return item.value - } else { - q.mu.Unlock() + q.nextPriority.Set(nextPriority) + return v.(priorityQueueItem).value } return nil } diff --git a/os/gtimer/gtimer_queue_heap.go b/os/gtimer/gtimer_queue_heap.go index 30879f770..c4b2f5dbe 100644 --- a/os/gtimer/gtimer_queue_heap.go +++ b/os/gtimer/gtimer_queue_heap.go @@ -12,6 +12,7 @@ func (h *priorityQueueHeap) Len() int { } // Less is used to implement the interface of sort.Interface. +// The least one is placed to the top of the heap. func (h *priorityQueueHeap) Less(i, j int) bool { return h.array[i].priority < h.array[j].priority } diff --git a/os/gtimer/gtimer_timer_loop.go b/os/gtimer/gtimer_timer_loop.go index 61e2ee672..ae94bd311 100644 --- a/os/gtimer/gtimer_timer_loop.go +++ b/os/gtimer/gtimer_timer_loop.go @@ -23,8 +23,7 @@ func (t *Timer) loop() { switch t.status.Val() { case StatusRunning: // Timer proceeding. - currentTimerTicks = t.ticks.Add(1) - if currentTimerTicks >= t.queue.LatestPriority() { + if currentTimerTicks = t.ticks.Add(1); currentTimerTicks >= t.queue.NextPriority() { t.proceed(currentTimerTicks) } @@ -40,7 +39,7 @@ func (t *Timer) loop() { }() } -// proceed proceeds the timer job checking and running logic. +// proceed function proceeds the timer job checking and running logic. func (t *Timer) proceed(currentTimerTicks int64) { var ( value interface{} @@ -51,9 +50,9 @@ func (t *Timer) proceed(currentTimerTicks int64) { break } entry := value.(*Entry) - // It checks if it meets the ticks requirement. + // It checks if it meets the ticks' requirement. if jobNextTicks := entry.nextTicks.Val(); currentTimerTicks < jobNextTicks { - // It push the job back if current ticks does not meet its running ticks requirement. + // It pushes the job back if current ticks does not meet its running ticks requirement. t.queue.Push(entry, entry.nextTicks.Val()) break } diff --git a/os/gtimer/gtimer_z_unit_timer_internal_test.go b/os/gtimer/gtimer_z_unit_timer_internal_test.go index 9882d21c3..e7c6d9777 100644 --- a/os/gtimer/gtimer_z_unit_timer_internal_test.go +++ b/os/gtimer/gtimer_z_unit_timer_internal_test.go @@ -46,3 +46,19 @@ func TestTimer_Proceed(t *testing.T) { t.Assert(array.Len(), 2) }) } + +func TestTimer_PriorityQueue(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + queue := newPriorityQueue() + queue.Push(1, 1) + queue.Push(4, 4) + queue.Push(5, 5) + queue.Push(2, 2) + queue.Push(3, 3) + t.Assert(queue.Pop(), 1) + t.Assert(queue.Pop(), 2) + t.Assert(queue.Pop(), 3) + t.Assert(queue.Pop(), 4) + t.Assert(queue.Pop(), 5) + }) +} From 0f6820df9e24070126a74ffe080bd0ced1011845 Mon Sep 17 00:00:00 2001 From: John Guo Date: Fri, 6 Aug 2021 14:13:37 +0800 Subject: [PATCH 08/11] add more unit testing case for package gtimer --- .../gtimer_z_unit_timer_internal_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/os/gtimer/gtimer_z_unit_timer_internal_test.go b/os/gtimer/gtimer_z_unit_timer_internal_test.go index e7c6d9777..785fd9823 100644 --- a/os/gtimer/gtimer_z_unit_timer_internal_test.go +++ b/os/gtimer/gtimer_z_unit_timer_internal_test.go @@ -62,3 +62,22 @@ func TestTimer_PriorityQueue(t *testing.T) { t.Assert(queue.Pop(), 5) }) } + +func TestTimer_PriorityQueue_FirstOneInArrayIsTheLeast(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + var ( + size = 1000000 + array = garray.NewIntArrayRange(0, size, 1) + ) + array.Shuffle() + queue := newPriorityQueue() + array.Iterator(func(k int, v int) bool { + queue.Push(v, int64(v)) + return true + }) + for i := 0; i < size; i++ { + t.Assert(queue.Pop(), i) + t.Assert(queue.heap.array[0].priority, i+1) + } + }) +} From cd3593182ab6e631756f8550604549b01a179bb7 Mon Sep 17 00:00:00 2001 From: John Guo Date: Sat, 7 Aug 2021 10:44:57 +0800 Subject: [PATCH 09/11] improve package gerror/ghttp for error code handling --- errors/gerror/gerror.go | 24 ++++++++++++++++++------ errors/gerror/gerror_code.go | 2 ++ errors/gerror/gerror_error.go | 2 +- net/ghttp/ghttp_func.go | 6 +++--- net/ghttp/ghttp_request_param.go | 9 +++++---- net/ghttp/ghttp_request_param_page.go | 19 +++++++++++++------ net/ghttp/ghttp_server.go | 2 +- net/ghttp/ghttp_server_handler.go | 6 +++--- net/ghttp/ghttp_server_router_serve.go | 7 ++++--- net/ghttp/ghttp_unit_config_test.go | 2 +- 10 files changed, 51 insertions(+), 28 deletions(-) diff --git a/errors/gerror/gerror.go b/errors/gerror/gerror.go index 29e14bb14..7e1e9af03 100644 --- a/errors/gerror/gerror.go +++ b/errors/gerror/gerror.go @@ -165,10 +165,14 @@ func NewCodef(code int, format string, args ...interface{}) error { // NewCodeSkip creates and returns an error which has error code and is formatted from given text. // The parameter specifies the stack callers skipped amount. -func NewCodeSkip(code, skip int, text string) error { +func NewCodeSkip(code, skip int, text ...string) error { + errText := "" + if len(text) > 0 { + errText = text[0] + } return &Error{ stack: callers(skip), - text: text, + text: errText, code: code, } } @@ -185,14 +189,18 @@ func NewCodeSkipf(code, skip int, format string, args ...interface{}) error { // WrapCode wraps error with code and text. // It returns nil if given err is nil. -func WrapCode(code int, err error, text string) error { +func WrapCode(code int, err error, text ...string) error { if err == nil { return nil } + errText := "" + if len(text) > 0 { + errText = text[0] + } return &Error{ error: err, stack: callers(), - text: text, + text: errText, code: code, } } @@ -214,14 +222,18 @@ func WrapCodef(code int, err error, format string, args ...interface{}) error { // WrapCodeSkip wraps error with code and text. // It returns nil if given err is nil. // The parameter specifies the stack callers skipped amount. -func WrapCodeSkip(code, skip int, err error, text string) error { +func WrapCodeSkip(code, skip int, err error, text ...string) error { if err == nil { return nil } + errText := "" + if len(text) > 0 { + errText = text[0] + } return &Error{ error: err, stack: callers(skip), - text: text, + text: errText, code: code, } } diff --git a/errors/gerror/gerror_code.go b/errors/gerror/gerror_code.go index c0eecc0f4..699deaa11 100644 --- a/errors/gerror/gerror_code.go +++ b/errors/gerror/gerror_code.go @@ -27,6 +27,7 @@ const ( CodeServerBusy = 63 // Server is busy, please try again later. CodeUnknown = 64 // Unknown error. CodeResourceNotExist = 65 // Resource does not exist. + CodeInvalidRequest = 66 // Invalid request. CodeBusinessValidationFailed = 300 // Business validation failed. ) @@ -51,6 +52,7 @@ var ( CodeServerBusy: "Server Is Busy", CodeUnknown: "Unknown Error", CodeResourceNotExist: "Resource Not Exist", + CodeInvalidRequest: "Invalid Request", CodeBusinessValidationFailed: "Business Validation Failed", } ) diff --git a/errors/gerror/gerror_error.go b/errors/gerror/gerror_error.go index 0c15b0410..97e22f0cd 100644 --- a/errors/gerror/gerror_error.go +++ b/errors/gerror/gerror_error.go @@ -51,7 +51,7 @@ func (err *Error) Error() string { errStr = Message(err.code) } if err.error != nil { - if err.text != "" { + if errStr != "" { errStr += ": " } errStr += err.error.Error() diff --git a/net/ghttp/ghttp_func.go b/net/ghttp/ghttp_func.go index 9b5e09be2..2c569c0ac 100644 --- a/net/ghttp/ghttp_func.go +++ b/net/ghttp/ghttp_func.go @@ -37,12 +37,12 @@ func niceCallFunc(f func()) { // of the real error point. if err, ok := exception.(error); ok { if gerror.Code(err) != gerror.CodeNil { - panic(gerror.Wrap(err, "")) + panic(err) } else { - panic(gerror.WrapCode(gerror.CodeInternalError, err, "")) + panic(gerror.WrapCodeSkip(gerror.CodeInternalError, 1, err, "")) } } else { - panic(gerror.NewCodeSkipf(gerror.CodeInternalError, 1, "%v", exception)) + panic(gerror.NewCodeSkipf(gerror.CodeInternalError, 1, "%+v", exception)) } } } diff --git a/net/ghttp/ghttp_request_param.go b/net/ghttp/ghttp_request_param.go index 1da2af60a..e0381e854 100644 --- a/net/ghttp/ghttp_request_param.go +++ b/net/ghttp/ghttp_request_param.go @@ -13,6 +13,7 @@ import ( "github.com/gogf/gf/encoding/gjson" "github.com/gogf/gf/encoding/gurl" "github.com/gogf/gf/encoding/gxml" + "github.com/gogf/gf/errors/gerror" "github.com/gogf/gf/internal/json" "github.com/gogf/gf/internal/utils" "github.com/gogf/gf/text/gregex" @@ -299,7 +300,7 @@ func (r *Request) parseQuery() { var err error r.queryMap, err = gstr.Parse(r.URL.RawQuery) if err != nil { - panic(err) + panic(gerror.WrapCode(gerror.CodeInvalidParameter, err, "")) } } } @@ -354,12 +355,12 @@ func (r *Request) parseForm() { if gstr.Contains(contentType, "multipart/") { // multipart/form-data, multipart/mixed if err = r.ParseMultipartForm(r.Server.config.FormParsingMemory); err != nil { - panic(err) + panic(gerror.WrapCode(gerror.CodeInvalidRequest, err, "")) } } else if gstr.Contains(contentType, "form") { // application/x-www-form-urlencoded if err = r.Request.ParseForm(); err != nil { - panic(err) + panic(gerror.WrapCode(gerror.CodeInvalidRequest, err, "")) } } if len(r.PostForm) > 0 { @@ -402,7 +403,7 @@ func (r *Request) parseForm() { } if params != "" { if r.formMap, err = gstr.Parse(params); err != nil { - panic(err) + panic(gerror.WrapCode(gerror.CodeInvalidParameter, err, "")) } } } diff --git a/net/ghttp/ghttp_request_param_page.go b/net/ghttp/ghttp_request_param_page.go index 20e0c8f55..b63a290a0 100644 --- a/net/ghttp/ghttp_request_param_page.go +++ b/net/ghttp/ghttp_request_param_page.go @@ -17,13 +17,15 @@ import ( // NOTE THAT the page parameter name from client is constantly defined as gpage.DefaultPageName // for simplification and convenience. func (r *Request) GetPage(totalSize, pageSize int) *gpage.Page { - // It must has Router object attribute. + // It must have Router object attribute. if r.Router == nil { panic("Router object not found") } - url := *r.URL - urlTemplate := url.Path - uriHasPageName := false + var ( + url = *r.URL + urlTemplate = url.Path + uriHasPageName = false + ) // Check the page variable in the URI. if len(r.Router.RegNames) > 0 { for _, name := range r.Router.RegNames { @@ -39,12 +41,17 @@ func (r *Request) GetPage(totalSize, pageSize int) *gpage.Page { for i, name := range r.Router.RegNames { rule := fmt.Sprintf(`[:\*]%s|\{%s\}`, name, name) if name == gpage.DefaultPageName { - urlTemplate, _ = gregex.ReplaceString(rule, gpage.DefaultPagePlaceHolder, urlTemplate) + urlTemplate, err = gregex.ReplaceString(rule, gpage.DefaultPagePlaceHolder, urlTemplate) } else { - urlTemplate, _ = gregex.ReplaceString(rule, match[i+1], urlTemplate) + urlTemplate, err = gregex.ReplaceString(rule, match[i+1], urlTemplate) + } + if err != nil { + panic(err) } } } + } else { + panic(err) } } } diff --git a/net/ghttp/ghttp_server.go b/net/ghttp/ghttp_server.go index 041b182e7..a0153aa0c 100644 --- a/net/ghttp/ghttp_server.go +++ b/net/ghttp/ghttp_server.go @@ -107,7 +107,7 @@ func GetServer(name ...interface{}) *Server { } // Initialize the server using default configurations. if err := s.SetConfig(NewConfig()); err != nil { - panic(err) + panic(gerror.WrapCode(gerror.CodeInvalidConfiguration, err, "")) } // Record the server to internal server mapping by name. serverMapping.Set(serverName, s) diff --git a/net/ghttp/ghttp_server_handler.go b/net/ghttp/ghttp_server_handler.go index e461a9222..7803a295d 100644 --- a/net/ghttp/ghttp_server_handler.go +++ b/net/ghttp/ghttp_server_handler.go @@ -68,12 +68,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { request.Response.WriteStatus(http.StatusInternalServerError) if err, ok := exception.(error); ok { if code := gerror.Code(err); code != gerror.CodeNil { - s.handleErrorLog(gerror.Wrap(err, ""), request) + s.handleErrorLog(err, request) } else { - s.handleErrorLog(gerror.WrapCode(gerror.CodeInternalError, err, ""), request) + s.handleErrorLog(gerror.WrapCodeSkip(gerror.CodeInternalError, 1, err, ""), request) } } else { - s.handleErrorLog(gerror.NewCodef(gerror.CodeInternalError, "%v", exception), request) + s.handleErrorLog(gerror.NewCodeSkipf(gerror.CodeInternalError, 1, "%+v", exception), request) } } } diff --git a/net/ghttp/ghttp_server_router_serve.go b/net/ghttp/ghttp_server_router_serve.go index 2f36302e1..d3614312e 100644 --- a/net/ghttp/ghttp_server_router_serve.go +++ b/net/ghttp/ghttp_server_router_serve.go @@ -8,6 +8,7 @@ package ghttp import ( "fmt" + "github.com/gogf/gf/errors/gerror" "github.com/gogf/gf/internal/json" "strings" @@ -175,8 +176,8 @@ func (s *Server) searchHandlers(method, path, domain string) (parsedItems []*han parsedItemList.PushBack(parsedItem) // The middleware is inserted before the serving handler. - // If there're multiple middleware, they're inserted into the result list by their registering order. - // The middleware are also executed by their registered order. + // If there are multiple middleware, they're inserted into the result list by their registering order. + // The middleware is also executed by their registered order. case handlerTypeMiddleware: if lastMiddlewareElem == nil { lastMiddlewareElem = parsedItemList.PushFront(parsedItem) @@ -190,7 +191,7 @@ func (s *Server) searchHandlers(method, path, domain string) (parsedItems []*han parsedItemList.PushBack(parsedItem) default: - panic(fmt.Sprintf(`invalid handler type %d`, item.Type)) + panic(gerror.NewCodef(gerror.CodeInternalError, `invalid handler type %d`, item.Type)) } } } diff --git a/net/ghttp/ghttp_unit_config_test.go b/net/ghttp/ghttp_unit_config_test.go index 95ba5abfb..cd5949b97 100644 --- a/net/ghttp/ghttp_unit_config_test.go +++ b/net/ghttp/ghttp_unit_config_test.go @@ -152,7 +152,7 @@ func Test_ClientMaxBodySize_File(t *testing.T) { defer gfile.Remove(path) t.Assert( gstr.Trim(c.PostContent("/", "name=john&file=@file:"+path)), - "http: request body too large", + "Invalid Request: http: request body too large", ) }) } From 9cd944fd775a4f0e5f247870be0a19c3a27ec157 Mon Sep 17 00:00:00 2001 From: John Guo Date: Sat, 7 Aug 2021 11:01:15 +0800 Subject: [PATCH 10/11] improve time maintaining feature for package gdb --- database/gdb/gdb_core.go | 9 ++++----- database/gdb/gdb_model_insert.go | 2 -- database/gdb/gdb_model_update.go | 4 ---- database/gdb/gdb_z_mysql_time_maintain_test.go | 11 +++++++---- 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/database/gdb/gdb_core.go b/database/gdb/gdb_core.go index 3b0cbe7f5..48512fc39 100644 --- a/database/gdb/gdb_core.go +++ b/database/gdb/gdb_core.go @@ -455,9 +455,8 @@ func (c *Core) formatOnDuplicate(columns []string, option DoInsertOption) string } } else { for _, column := range columns { - // If it's SAVE operation, - // do not automatically update the creating time. - if c.isSoftCreatedFilledName(column) { + // If it's SAVE operation, do not automatically update the creating time. + if c.isSoftCreatedFieldName(column) { continue } if len(onDuplicateStr) > 0 { @@ -679,8 +678,8 @@ func (c *Core) HasTable(name string) (bool, error) { return false, nil } -// isSoftCreatedFilledName checks and returns whether given filed name is an automatic-filled created time. -func (c *Core) isSoftCreatedFilledName(fieldName string) bool { +// isSoftCreatedFieldName checks and returns whether given filed name is an automatic-filled created time. +func (c *Core) isSoftCreatedFieldName(fieldName string) bool { if fieldName == "" { return false } diff --git a/database/gdb/gdb_model_insert.go b/database/gdb/gdb_model_insert.go index 6f29229d4..90250c81b 100644 --- a/database/gdb/gdb_model_insert.go +++ b/database/gdb/gdb_model_insert.go @@ -217,7 +217,6 @@ func (m *Model) doInsertWithOption(insertOption int) (result sql.Result, err err nowString = gtime.Now().String() fieldNameCreate = m.getSoftFieldNameCreated() fieldNameUpdate = m.getSoftFieldNameUpdated() - fieldNameDelete = m.getSoftFieldNameDeleted() ) newData, err := m.filterDataForInsertOrUpdate(m.data) if err != nil { @@ -286,7 +285,6 @@ func (m *Model) doInsertWithOption(insertOption int) (result sql.Result, err err // Automatic handling for creating/updating time. if !m.unscoped && (fieldNameCreate != "" || fieldNameUpdate != "") { for k, v := range list { - gutil.MapDelete(v, fieldNameCreate, fieldNameUpdate, fieldNameDelete) if fieldNameCreate != "" { v[fieldNameCreate] = nowString } diff --git a/database/gdb/gdb_model_update.go b/database/gdb/gdb_model_update.go index 80d7ad2a8..12f2ab492 100644 --- a/database/gdb/gdb_model_update.go +++ b/database/gdb/gdb_model_update.go @@ -15,7 +15,6 @@ import ( "github.com/gogf/gf/os/gtime" "github.com/gogf/gf/text/gstr" "github.com/gogf/gf/util/gconv" - "github.com/gogf/gf/util/gutil" ) // Update does "UPDATE ... " statement for the model. @@ -43,9 +42,7 @@ func (m *Model) Update(dataAndWhere ...interface{}) (result sql.Result, err erro } var ( updateData = m.data - fieldNameCreate = m.getSoftFieldNameCreated() fieldNameUpdate = m.getSoftFieldNameUpdated() - fieldNameDelete = m.getSoftFieldNameDeleted() conditionWhere, conditionExtra, conditionArgs = m.formatCondition(false, false) ) // Automatically update the record updating time. @@ -61,7 +58,6 @@ func (m *Model) Update(dataAndWhere ...interface{}) (result sql.Result, err erro switch refKind { case reflect.Map, reflect.Struct: dataMap := ConvertDataForTableRecord(m.data) - gutil.MapDelete(dataMap, fieldNameCreate, fieldNameUpdate, fieldNameDelete) if fieldNameUpdate != "" { dataMap[fieldNameUpdate] = gtime.Now().String() } diff --git a/database/gdb/gdb_z_mysql_time_maintain_test.go b/database/gdb/gdb_z_mysql_time_maintain_test.go index 120a4cd55..860518fc7 100644 --- a/database/gdb/gdb_z_mysql_time_maintain_test.go +++ b/database/gdb/gdb_z_mysql_time_maintain_test.go @@ -663,6 +663,9 @@ CREATE TABLE %s ( } defer dropTable(table) + //db.SetDebug(true) + //defer db.SetDebug(false) + type Entity struct { Id uint64 `orm:"id,primary" json:"id"` Name string `orm:"name" json:"name"` @@ -679,7 +682,7 @@ CREATE TABLE %s ( UpdateAt: nil, DeleteAt: nil, } - r, err := db.Model(table).Data(dataInsert).Insert() + r, err := db.Model(table).Data(dataInsert).OmitEmpty().Insert() t.AssertNil(err) n, _ := r.RowsAffected() t.Assert(n, 1) @@ -702,7 +705,7 @@ CREATE TABLE %s ( UpdateAt: nil, DeleteAt: nil, } - r, err = db.Model(table).Data(dataSave).Save() + r, err = db.Model(table).Data(dataSave).OmitEmpty().Save() t.AssertNil(err) n, _ = r.RowsAffected() t.Assert(n, 2) @@ -726,7 +729,7 @@ CREATE TABLE %s ( UpdateAt: nil, DeleteAt: nil, } - r, err = db.Model(table).Data(dataUpdate).WherePri(1).Update() + r, err = db.Model(table).Data(dataUpdate).WherePri(1).OmitEmpty().Update() t.AssertNil(err) n, _ = r.RowsAffected() t.Assert(n, 1) @@ -747,7 +750,7 @@ CREATE TABLE %s ( UpdateAt: nil, DeleteAt: nil, } - r, err = db.Model(table).Data(dataReplace).Replace() + r, err = db.Model(table).Data(dataReplace).OmitEmpty().Replace() t.AssertNil(err) n, _ = r.RowsAffected() t.Assert(n, 2) From 4eb057227c8f55bed5d9d416786a4dbc48501043 Mon Sep 17 00:00:00 2001 From: John Guo Date: Sat, 7 Aug 2021 11:59:30 +0800 Subject: [PATCH 11/11] add SizeFormat function for package gfile; add more internal logging for rotation feature for pacakge glog --- os/gfile/gfile_size.go | 5 +++++ os/gfile/gfile_z_size_test.go | 19 +++++++++++++++++++ os/glog/glog_logger_rotate.go | 8 ++++++++ os/gmlock/gmlock_locker.go | 10 +++++----- 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/os/gfile/gfile_size.go b/os/gfile/gfile_size.go index 615b9e765..9e3d8f0a6 100644 --- a/os/gfile/gfile_size.go +++ b/os/gfile/gfile_size.go @@ -22,6 +22,11 @@ func Size(path string) int64 { return s.Size() } +// SizeFormat returns the size of file specified by in format string. +func SizeFormat(path string) string { + return FormatSize(Size(path)) +} + // ReadableSize formats size of file given by , for more human readable. func ReadableSize(path string) string { return FormatSize(Size(path)) diff --git a/os/gfile/gfile_z_size_test.go b/os/gfile/gfile_z_size_test.go index 481f84ef7..9425fa866 100644 --- a/os/gfile/gfile_z_size_test.go +++ b/os/gfile/gfile_z_size_test.go @@ -33,6 +33,25 @@ func Test_Size(t *testing.T) { }) } +func Test_SizeFormat(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + var ( + paths1 = "/testfile_t1.txt" + sizes string + ) + + createTestFile(paths1, "abcdefghijklmn") + defer delTestFiles(paths1) + + sizes = gfile.SizeFormat(testpath() + paths1) + t.Assert(sizes, "14.00B") + + sizes = gfile.SizeFormat("") + t.Assert(sizes, "0.00B") + + }) +} + func Test_StrToSize(t *testing.T) { gtest.C(t, func(t *gtest.T) { t.Assert(gfile.StrToSize("0.00B"), 0) diff --git a/os/glog/glog_logger_rotate.go b/os/glog/glog_logger_rotate.go index 697793854..9262b989b 100644 --- a/os/glog/glog_logger_rotate.go +++ b/os/glog/glog_logger_rotate.go @@ -43,6 +43,13 @@ func (l *Logger) doRotateFile(filePath string) error { } defer gmlock.Unlock(memoryLockKey) + intlog.PrintFunc(l.ctx, func() string { + return fmt.Sprintf(`start rotating file by size: %s, file: %s`, gfile.SizeFormat(filePath), filePath) + }) + defer intlog.PrintFunc(l.ctx, func() string { + return fmt.Sprintf(`done rotating file by size: %s, size: %s`, gfile.SizeFormat(filePath), filePath) + }) + // No backups, it then just removes the current logging file. if l.config.RotateBackupLimit == 0 { if err := gfile.Remove(filePath); err != nil { @@ -90,6 +97,7 @@ func (l *Logger) doRotateFile(filePath string) error { intlog.Printf(l.ctx, `rotation file exists, continue: %s`, newFilePath) } } + intlog.Printf(l.ctx, "rotating file by size from %s to %s", filePath, newFilePath) if err := gfile.Rename(filePath, newFilePath); err != nil { return err } diff --git a/os/gmlock/gmlock_locker.go b/os/gmlock/gmlock_locker.go index 11f195057..075d139e2 100644 --- a/os/gmlock/gmlock_locker.go +++ b/os/gmlock/gmlock_locker.go @@ -11,9 +11,9 @@ import ( "github.com/gogf/gf/os/gmutex" ) -// Memory locker. +// Locker is a memory based locker. // Note that there's no cache expire mechanism for mutex in locker. -// You need remove certain mutex manually when you do not want use it any more. +// You need remove certain mutex manually when you do not want use it anymore. type Locker struct { m *gmap.StrAnyMap } @@ -28,7 +28,7 @@ func New() *Locker { // Lock locks the with writing lock. // If there's a write/reading lock the , -// it will blocks until the lock is released. +// it will block until the lock is released. func (l *Locker) Lock(key string) { l.getOrNewMutex(key).Lock() } @@ -68,7 +68,7 @@ func (l *Locker) RUnlock(key string) { // LockFunc locks the with writing lock and callback function . // If there's a write/reading lock the , -// it will blocks until the lock is released. +// it will block until the lock is released. // // It releases the lock after is executed. func (l *Locker) LockFunc(key string, f func()) { @@ -79,7 +79,7 @@ func (l *Locker) LockFunc(key string, f func()) { // RLockFunc locks the with reading lock and callback function . // If there's a writing lock the , -// it will blocks until the lock is released. +// it will block until the lock is released. // // It releases the lock after is executed. func (l *Locker) RLockFunc(key string, f func()) {