sh를 통으로 atomic하게 교체

This commit is contained in:
2023-08-16 21:44:19 +09:00
parent c7f073c779
commit 42b4ade782
4 changed files with 56 additions and 42 deletions

View File

@ -257,8 +257,7 @@ func (caller apiCaller) serviceAPI(w http.ResponseWriter, r *http.Request) error
atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(&newService)) atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(&newService))
} }
serptr := atomic.LoadPointer(&mg.service().serviceSerialized) w.Write(mg.service().divisionsSerialized)
w.Write(*(*[]byte)(serptr))
} else if r.Method == "POST" { } else if r.Method == "POST" {
body, _ := io.ReadAll(r.Body) body, _ := io.ReadAll(r.Body)
var service serviceDescription var service serviceDescription
@ -293,8 +292,7 @@ func (caller apiCaller) serviceAPI(w http.ResponseWriter, r *http.Request) error
func (caller apiCaller) maintenanceAPI(w http.ResponseWriter, r *http.Request) error { func (caller apiCaller) maintenanceAPI(w http.ResponseWriter, r *http.Request) error {
mg := caller.mg mg := caller.mg
if r.Method == "GET" { if r.Method == "GET" {
serptr := atomic.LoadPointer(&mg.service().divisionsSerialized) w.Write(mg.service().divisionsSerialized)
w.Write(*(*[]byte)(serptr))
} else if r.Method == "POST" { } else if r.Method == "POST" {
var divs map[string]*Division var divs map[string]*Division
dec := json.NewDecoder(r.Body) dec := json.NewDecoder(r.Body)

View File

@ -501,7 +501,7 @@ func (mg *Maingate) RegisterHandlers(ctx context.Context, serveMux *http.ServeMu
logger.Println("Service is registered :", mg.service().ServiceCode) logger.Println("Service is registered :", mg.service().ServiceCode)
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, mg.service().ServiceCode, "/"), func(w http.ResponseWriter, r *http.Request) { serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, mg.service().ServiceCode, "/"), func(w http.ResponseWriter, r *http.Request) {
mg.service().ServeHTTP(w, r) mg.service().serveHTTP(w, r)
}) })
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "api/"), mg.api) serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "api/"), mg.api)
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "query/"), mg.query) serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "query/"), mg.query)

View File

@ -131,13 +131,13 @@ type serviceDescription struct {
ServiceDescriptionSummary `bson:",inline" json:",inline"` ServiceDescriptionSummary `bson:",inline" json:",inline"`
Divisions map[string]*Division `bson:"divisions" json:"divisions"` Divisions map[string]*Division `bson:"divisions" json:"divisions"`
ServerApiTokens []primitive.ObjectID `bson:"api_tokens" json:"api_tokens"` ServerApiTokens []primitive.ObjectID `bson:"api_tokens" json:"api_tokens"`
Admins []string `bson:"admins" json:"admins"` MaximumNumLinkAccount int64
VersionSplits map[string]string `bson:"version_splits" json:"version_splits"`
auths *gocommon.AuthCollection auths *gocommon.AuthCollection
wl *whitelist wl *whitelist
mongoClient gocommon.MongoClient mongoClient gocommon.MongoClient
sessionTTL time.Duration sessionTTL time.Duration
MaximumNumLinkAccount int64
serviceCodeBytes []byte serviceCodeBytes []byte
getUserBrowserInfo func(r *http.Request) (string, error) getUserBrowserInfo func(r *http.Request) (string, error)
@ -145,11 +145,11 @@ type serviceDescription struct {
updateUserinfo func(info usertokeninfo) (bool, string, string) updateUserinfo func(info usertokeninfo) (bool, string, string)
getProviderInfo func(platform string, uid string) (string, string, error) getProviderInfo func(platform string, uid string) (string, string, error)
admins unsafe.Pointer divisionsForUsersSerialized []byte
divisionsForUsersSerialized unsafe.Pointer divisionsSerialized []byte
divisionsSerialized unsafe.Pointer serviceSerialized []byte
serviceSerialized unsafe.Pointer serviceSummarySerialized []byte
serviceSummarySerialized unsafe.Pointer divisionsSplits map[string][]byte
} }
func (sh *serviceDescription) isValidToken(apiToken primitive.ObjectID) bool { func (sh *serviceDescription) isValidToken(apiToken primitive.ObjectID) bool {
@ -211,7 +211,9 @@ func (sh *serviceDescription) prepare(mg *Maingate) error {
} }
divsForUsers := make(map[string]*DivisionForUser) divsForUsers := make(map[string]*DivisionForUser)
var namesOnly []string
for dn, div := range divs { for dn, div := range divs {
namesOnly = append(namesOnly, dn)
if div.State == DivisionState_Closed { if div.State == DivisionState_Closed {
continue continue
} }
@ -249,13 +251,25 @@ func (sh *serviceDescription) prepare(mg *Maingate) error {
} }
} }
divmarshaled, _ := json.Marshal(divs) sh.divisionsSerialized, _ = json.Marshal(divs)
devstr := string(divmarshaled) sh.divisionsForUsersSerialized, _ = json.Marshal(divsForUsers)
sh.divisionsSerialized = unsafe.Pointer(&devstr)
divmarshaled2, _ := json.Marshal(divsForUsers) if len(sh.VersionSplits) == 0 {
devstr2 := string(divmarshaled2) sh.VersionSplits = map[string]string{
sh.divisionsForUsersSerialized = unsafe.Pointer(&devstr2) "": strings.Join(namesOnly, ","),
}
}
sh.divisionsSplits = make(map[string][]byte)
for ver, divnamesT := range sh.VersionSplits {
divnames := strings.Split(divnamesT, ",")
split := make(map[string]*DivisionForUser)
for _, divname := range divnames {
split[divname] = divsForUsers[divname]
}
splitMarshaled, _ := json.Marshal(split)
sh.divisionsSplits[ver] = splitMarshaled
}
sh.MaximumNumLinkAccount = mg.maingateConfig.MaximumNumLinkAccount sh.MaximumNumLinkAccount = mg.maingateConfig.MaximumNumLinkAccount
sh.mongoClient = mg.mongoClient sh.mongoClient = mg.mongoClient
@ -267,19 +281,11 @@ func (sh *serviceDescription) prepare(mg *Maingate) error {
sh.updateUserinfo = mg.updateUserinfo sh.updateUserinfo = mg.updateUserinfo
sh.getProviderInfo = mg.getProviderInfo sh.getProviderInfo = mg.getProviderInfo
if sh.Admins == nil {
sh.Admins = []string{}
}
sh.admins = unsafe.Pointer(&sh.Admins)
sh.wl = &mg.wl sh.wl = &mg.wl
bt, _ := json.Marshal(sh) sh.divisionsSerialized, _ = json.Marshal(sh)
atomic.StorePointer(&sh.serviceSerialized, unsafe.Pointer(&bt)) sh.serviceSummarySerialized, _ = json.Marshal(sh.ServiceDescriptionSummary)
btsum, _ := json.Marshal(sh.ServiceDescriptionSummary) logger.Println("service is ready :", sh.ServiceCode, string(sh.divisionsSerialized))
atomic.StorePointer(&sh.serviceSummarySerialized, unsafe.Pointer(&btsum))
logger.Println("service is ready :", sh.ServiceCode, sh.Admins, string(divmarshaled))
return nil return nil
} }
@ -743,7 +749,20 @@ func (sh *serviceDescription) authorize(w http.ResponseWriter, r *http.Request)
} }
} }
func (sh *serviceDescription) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (sh *serviceDescription) findVersionSplit(version string) []byte {
if len(version) > 0 {
for k, v := range sh.divisionsSplits {
if strings.HasPrefix(version, k) {
if version == k || version[len(k)] == '.' {
return v
}
}
}
}
return sh.divisionsSplits[""]
}
func (sh *serviceDescription) serveHTTP(w http.ResponseWriter, r *http.Request) {
defer func() { defer func() {
s := recover() s := recover()
if s != nil { if s != nil {
@ -784,9 +803,8 @@ func (sh *serviceDescription) ServeHTTP(w http.ResponseWriter, r *http.Request)
return return
} }
divstrptr := atomic.LoadPointer(&sh.divisionsForUsersSerialized) version := queryvals.Get("version")
divstr := *(*string)(divstrptr) w.Write(sh.findVersionSplit(version))
w.Write([]byte(divstr))
} else if strings.HasSuffix(r.URL.Path, "/addr") { } else if strings.HasSuffix(r.URL.Path, "/addr") {
queryvals := r.URL.Query() queryvals := r.URL.Query()
sk := queryvals.Get("sk") sk := queryvals.Get("sk")

View File

@ -285,11 +285,9 @@ func (mg *Maingate) watchServiceCollection(parentctx context.Context, serveMux *
logger.Error("service cannot be prepared :", data.Service, err) logger.Error("service cannot be prepared :", data.Service, err)
} else { } else {
// 내가 임시로 가지고 있던 서비스일 수 있다. // 내가 임시로 가지고 있던 서비스일 수 있다.
already := mg.service().Id == data.Service.Id if mg.service().Id == data.Service.Id {
logger.Println("service is on the board! :", data.Service) logger.Println("service is on the board! :", data.Service)
atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(data.Service)) atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(data.Service))
if !already {
serveMux.Handle(gocommon.MakeHttpHandlerPattern(prefix, data.Service.ServiceCode, "/"), mg.service())
} }
} }