From bf4d2fd77ce42ae8a2098f24cde9f59833253361 Mon Sep 17 00:00:00 2001 From: Nagarei Date: Wed, 7 Jul 2021 15:57:21 +0900 Subject: [PATCH 01/43] fix(bench): browserGetIsuGraphAction --- bench/scenario/action.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bench/scenario/action.go b/bench/scenario/action.go index 599ece66e..db895cce1 100644 --- a/bench/scenario/action.go +++ b/bench/scenario/action.go @@ -727,7 +727,9 @@ func browserGetIsuConditionAction(ctx context.Context, a *agent.Agent, id string return isu, conditions, errors } -func browserGetIsuGraph(ctx context.Context, a *agent.Agent, id string, date uint64) (*service.Isu, []*service.GraphResponse, []error) { +func browserGetIsuGraphAction(ctx context.Context, a *agent.Agent, id string, date uint64, + validateGraph func(*http.Response, []*service.GraphResponse) []error, +) (*service.Isu, []*service.GraphResponse, []error) { // TODO: 静的ファイルのGET errors := []error{} @@ -736,9 +738,11 @@ func browserGetIsuGraph(ctx context.Context, a *agent.Agent, id string, date uin if err != nil { errors = append(errors, err) } - graph, _, err := getIsuGraphAction(ctx, a, id, date) + graph, res, err := getIsuGraphAction(ctx, a, id, date) if err != nil { errors = append(errors, err) + } else { + errors = append(errors, validateGraph(res, graph)...) } return isu, graph, errors } From badbcb125739b1e106d89ad31a9466474ea2dae8 Mon Sep 17 00:00:00 2001 From: Nagarei Date: Wed, 7 Jul 2021 18:29:53 +0900 Subject: [PATCH 02/43] feat(bench): add graph scenario --- bench/scenario/action.go | 3 ++ bench/scenario/load.go | 113 +++++++++++++++++++++++++++++++-------- 2 files changed, 94 insertions(+), 22 deletions(-) diff --git a/bench/scenario/action.go b/bench/scenario/action.go index db895cce1..e193e0edf 100644 --- a/bench/scenario/action.go +++ b/bench/scenario/action.go @@ -585,6 +585,9 @@ func getIsuGraphAction(ctx context.Context, a *agent.Agent, id string, date uint if err != nil { return nil, nil, err } + + //TODO: バリデーション + return graph, res, nil } diff --git a/bench/scenario/load.go b/bench/scenario/load.go index b86cb77cc..179786ee1 100644 --- a/bench/scenario/load.go +++ b/bench/scenario/load.go @@ -217,27 +217,7 @@ scenarioLoop: } //conditionを確認して、椅子状態を改善 - //TODO: すでに改善済みのものを弾く - solvedCondition := model.IsuStateChangeNone - for _, c := range conditions { - //MEMO: 重かったらフォーマットが想定通りの前提で最適化する - for _, cond := range strings.Split(c.Condition, ",") { - keyValue := strings.Split(cond, "=") - if len(keyValue) != 2 { - continue //形式に従っていないものは無視 - } - if keyValue[1] != "false" { - if keyValue[0] == "is_dirty" { - solvedCondition |= model.IsuStateChangeClear - } else if keyValue[0] == "is_overweight" { - solvedCondition |= model.IsuStateChangeDetectOverweight - } else if keyValue[0] == "is_broken" { - solvedCondition |= model.IsuStateChangeRepair - } - } - } - } - + solvedCondition := findBadIsuState(conditions) if solvedCondition != model.IsuStateChangeNone { //TODO: graph @@ -246,8 +226,97 @@ scenarioLoop: } else { //TODO: graphを見に行くシナリオ + virtualNow := s.ToVirtualTime(time.Now()) + virtualToday := time.Date(virtualNow.Year(), virtualNow.Month(), virtualNow.Day(), 0, 0, 0, 0, virtualNow.Location()) + _, graphToday, errs := browserGetIsuGraphAction(ctx, user.Agent, targetIsu.JIAIsuUUID, uint64(virtualToday.Unix()), + func(res *http.Response, graph []*service.GraphResponse) []error { + return []error{} //TODO: 検証 + }, + ) + for _, err := range errs { + scenarioSuccess = false + step.AddError(err) + } + if len(errs) > 0 { + continue scenarioLoop + } + + //前日のグラフ + _, _, errs = browserGetIsuGraphAction(ctx, user.Agent, targetIsu.JIAIsuUUID, uint64(virtualToday.Add(-24*time.Hour).Unix()), + func(res *http.Response, graph []*service.GraphResponse) []error { + return []error{} //TODO: 検証 + }, + ) + for _, err := range errs { + scenarioSuccess = false + step.AddError(err) + } + if len(errs) > 0 { + continue scenarioLoop + } + + //悪いものを探す + var errorEndAtUnix int64 = 0 + for _, g := range graphToday { + if g.Data.Score < 100 { + errorEndAtUnix = g.StartAt + } + } + + //悪いものがあれば、そのconditionを取る + if errorEndAtUnix != 0 { + _, conditions, errs := browserGetIsuConditionAction(ctx, user.Agent, targetIsu.JIAIsuUUID, + service.GetIsuConditionRequest{ + StartTime: nil, + CursorEndTime: uint64(errorEndAtUnix), + CursorJIAIsuUUID: "", + ConditionLevel: "info,warning,critical", + Limit: nil, + }, + func(res *http.Response, conditions []*service.GetIsuConditionResponse) []error { + return []error{} + //TODO: 検証 + }, + ) + for _, err := range errs { + scenarioSuccess = false + step.AddError(err) + } + if len(errs) > 0 { + continue scenarioLoop + } + + solvedCondition := findBadIsuState(conditions) + if solvedCondition != model.IsuStateChangeNone { + go func() { targetIsu.StreamsForScenario.StateChan <- solvedCondition }() + } + } } + } +} - //TODO: 椅子の追加 +func findBadIsuState(conditions []*service.GetIsuConditionResponse) model.IsuStateChange { + //TODO: すでに改善済みのものを弾く + + solvedCondition := model.IsuStateChangeNone + for _, c := range conditions { + //MEMO: 重かったらフォーマットが想定通りの前提で最適化する + for _, cond := range strings.Split(c.Condition, ",") { + keyValue := strings.Split(cond, "=") + if len(keyValue) != 2 { + continue //形式に従っていないものは無視 + } + if keyValue[1] != "false" { + if keyValue[0] == "is_dirty" { + solvedCondition |= model.IsuStateChangeClear + } else if keyValue[0] == "is_overweight" { + solvedCondition |= model.IsuStateChangeDetectOverweight + } else if keyValue[0] == "is_broken" { + solvedCondition |= model.IsuStateChangeRepair + } + } + } } + + return solvedCondition } From da9d72c9676ff77765a39296dc1cbf5ad0b9a980 Mon Sep 17 00:00:00 2001 From: Nagarei Date: Wed, 7 Jul 2021 21:22:43 +0900 Subject: [PATCH 03/43] =?UTF-8?q?fieat(bench):=20graph=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bench/scenario/load.go | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/bench/scenario/load.go b/bench/scenario/load.go index 179786ee1..5f0ae1b97 100644 --- a/bench/scenario/load.go +++ b/bench/scenario/load.go @@ -217,9 +217,19 @@ scenarioLoop: } //conditionを確認して、椅子状態を改善 - solvedCondition := findBadIsuState(conditions) + solvedCondition, timestamp := findBadIsuState(conditions) if solvedCondition != model.IsuStateChangeNone { - //TODO: graph + //graphを見る + virtualDay := (timestamp / (24 * 60 * 60)) * (24 * 60 * 60) + _, _, errs := browserGetIsuGraphAction(ctx, user.Agent, targetIsu.JIAIsuUUID, uint64(virtualDay), + func(res *http.Response, graph []*service.GraphResponse) []error { + return []error{} //TODO: 検証 + }, + ) + for _, err := range errs { + scenarioSuccess = false + step.AddError(err) + } go func() { targetIsu.StreamsForScenario.StateChan <- solvedCondition }() } @@ -258,16 +268,17 @@ scenarioLoop: //悪いものを探す var errorEndAtUnix int64 = 0 for _, g := range graphToday { - if g.Data.Score < 100 { + if g.Data != nil && g.Data.Score < 100 { errorEndAtUnix = g.StartAt } } //悪いものがあれば、そのconditionを取る if errorEndAtUnix != 0 { + startTime := uint64(errorEndAtUnix - 60*60) _, conditions, errs := browserGetIsuConditionAction(ctx, user.Agent, targetIsu.JIAIsuUUID, service.GetIsuConditionRequest{ - StartTime: nil, + StartTime: &startTime, CursorEndTime: uint64(errorEndAtUnix), CursorJIAIsuUUID: "", ConditionLevel: "info,warning,critical", @@ -286,7 +297,7 @@ scenarioLoop: continue scenarioLoop } - solvedCondition := findBadIsuState(conditions) + solvedCondition, _ := findBadIsuState(conditions) if solvedCondition != model.IsuStateChangeNone { go func() { targetIsu.StreamsForScenario.StateChan <- solvedCondition }() } @@ -295,18 +306,21 @@ scenarioLoop: } } -func findBadIsuState(conditions []*service.GetIsuConditionResponse) model.IsuStateChange { +func findBadIsuState(conditions []*service.GetIsuConditionResponse) (model.IsuStateChange, int64) { //TODO: すでに改善済みのものを弾く + var virtualTimestamp int64 solvedCondition := model.IsuStateChangeNone for _, c := range conditions { //MEMO: 重かったらフォーマットが想定通りの前提で最適化する + bad := false for _, cond := range strings.Split(c.Condition, ",") { keyValue := strings.Split(cond, "=") if len(keyValue) != 2 { continue //形式に従っていないものは無視 } if keyValue[1] != "false" { + bad = true if keyValue[0] == "is_dirty" { solvedCondition |= model.IsuStateChangeClear } else if keyValue[0] == "is_overweight" { @@ -316,7 +330,10 @@ func findBadIsuState(conditions []*service.GetIsuConditionResponse) model.IsuSta } } } + if bad { + virtualTimestamp = c.Timestamp + } } - return solvedCondition + return solvedCondition, virtualTimestamp } From cc38ca3e18b94adf5faaacf04c715265cdb55913 Mon Sep 17 00:00:00 2001 From: Nagarei Date: Wed, 7 Jul 2021 21:50:46 +0900 Subject: [PATCH 04/43] =?UTF-8?q?fix(bench):=20=E5=8F=8D=E6=98=A0=E6=B8=88?= =?UTF-8?q?=E3=81=BF=E3=81=AE=E3=82=82=E3=81=AE=E3=81=A7=E3=81=AF=E7=8A=B6?= =?UTF-8?q?=E6=85=8B=E6=94=B9=E5=96=84=E3=81=97=E3=81=AA=E3=81=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bench/scenario/load.go | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/bench/scenario/load.go b/bench/scenario/load.go index 5f0ae1b97..44512d94b 100644 --- a/bench/scenario/load.go +++ b/bench/scenario/load.go @@ -89,6 +89,7 @@ func (s *Scenario) loadNormalUser(ctx context.Context, step *isucandar.Benchmark nextTargetIsuIndex := 0 scenarioDoneCount := 0 scenarioSuccess := false + lastSolvedTime := s.virtualTimeStart scenarioLoop: for { select { @@ -186,7 +187,7 @@ scenarioLoop: scenarioSuccess = false step.AddError(err) } - if len(errs) > 0 { + if len(errs) > 0 || len(conditions) == 0 { continue scenarioLoop } @@ -217,10 +218,10 @@ scenarioLoop: } //conditionを確認して、椅子状態を改善 - solvedCondition, timestamp := findBadIsuState(conditions) - if solvedCondition != model.IsuStateChangeNone { + solvedCondition, findTimestamp := findBadIsuState(conditions) + if solvedCondition != model.IsuStateChangeNone && lastSolvedTime.Before(time.Unix(findTimestamp, 0)) { //graphを見る - virtualDay := (timestamp / (24 * 60 * 60)) * (24 * 60 * 60) + virtualDay := (findTimestamp / (24 * 60 * 60)) * (24 * 60 * 60) _, _, errs := browserGetIsuGraphAction(ctx, user.Agent, targetIsu.JIAIsuUUID, uint64(virtualDay), func(res *http.Response, graph []*service.GraphResponse) []error { return []error{} //TODO: 検証 @@ -231,6 +232,8 @@ scenarioLoop: step.AddError(err) } + //状態改善 + lastSolvedTime = time.Unix(findTimestamp, 0) go func() { targetIsu.StreamsForScenario.StateChan <- solvedCondition }() } } else { @@ -297,8 +300,10 @@ scenarioLoop: continue scenarioLoop } - solvedCondition, _ := findBadIsuState(conditions) - if solvedCondition != model.IsuStateChangeNone { + //状態改善 + solvedCondition, findTimestamp := findBadIsuState(conditions) + if solvedCondition != model.IsuStateChangeNone && lastSolvedTime.Before(time.Unix(findTimestamp, 0)) { + lastSolvedTime = time.Unix(findTimestamp, 0) go func() { targetIsu.StreamsForScenario.StateChan <- solvedCondition }() } } @@ -330,7 +335,7 @@ func findBadIsuState(conditions []*service.GetIsuConditionResponse) (model.IsuSt } } } - if bad { + if bad && virtualTimestamp == 0 { virtualTimestamp = c.Timestamp } } From 6c11d7db30a96c1b03fc61d3320a1a1aebb1526e Mon Sep 17 00:00:00 2001 From: Nagarei Date: Thu, 8 Jul 2021 11:27:21 +0900 Subject: [PATCH 05/43] =?UTF-8?q?fix(bench):=20chan=E3=81=AE=E5=9B=9E?= =?UTF-8?q?=E6=95=B0=E3=82=92=E6=B8=9B=E3=82=89=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bench/model/isu.go | 6 +++--- bench/scenario/load.go | 8 ++++---- bench/scenario/posting.go | 16 +++++++--------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/bench/model/isu.go b/bench/model/isu.go index 3c84bf5e0..20d734de7 100644 --- a/bench/model/isu.go +++ b/bench/model/isu.go @@ -21,7 +21,7 @@ const ( type StreamsForPoster struct { ActiveChan chan<- bool StateChan <-chan IsuStateChange - ConditionChan chan<- *IsuCondition + ConditionChan chan<- []IsuCondition } //posterスレッドとシナリオスレッドとの通信に必要な情報 @@ -30,7 +30,7 @@ type StreamsForPoster struct { type StreamsForScenario struct { activeChan <-chan bool StateChan chan<- IsuStateChange - ConditionChan <-chan *IsuCondition + ConditionChan <-chan []IsuCondition } //一つのIsuにつき、一つの送信用スレッドがある @@ -56,7 +56,7 @@ type Isu struct { func NewRandomIsuRaw(owner *User) (*Isu, *StreamsForPoster, error) { activeChan := make(chan bool) stateChan := make(chan IsuStateChange, 1) - conditionChan := make(chan *IsuCondition, 30) + conditionChan := make(chan []IsuCondition, 10) id := fmt.Sprintf("randomid-%s-%d", owner.UserID, len(owner.IsuListOrderByCreatedAt)) //TODO: ちゃんと生成する name := fmt.Sprintf("randomname-%s-%d", owner.UserID, len(owner.IsuListOrderByCreatedAt)) //TODO: ちゃんと生成する diff --git a/bench/scenario/load.go b/bench/scenario/load.go index 44512d94b..6431c736f 100644 --- a/bench/scenario/load.go +++ b/bench/scenario/load.go @@ -121,11 +121,11 @@ scenarioLoop: select { case <-ctx.Done(): return - case cond, ok := <-isu.StreamsForScenario.ConditionChan: + case conditions, ok := <-isu.StreamsForScenario.ConditionChan: if !ok { break getConditionFromPosterLoop } - isu.Conditions = append(isu.Conditions, *cond) + isu.Conditions = append(isu.Conditions, conditions...) default: break getConditionFromPosterLoop } @@ -234,7 +234,7 @@ scenarioLoop: //状態改善 lastSolvedTime = time.Unix(findTimestamp, 0) - go func() { targetIsu.StreamsForScenario.StateChan <- solvedCondition }() + targetIsu.StreamsForScenario.StateChan <- solvedCondition //バッファがあるのでブロック率は低い読みで直列に投げる } } else { @@ -304,7 +304,7 @@ scenarioLoop: solvedCondition, findTimestamp := findBadIsuState(conditions) if solvedCondition != model.IsuStateChangeNone && lastSolvedTime.Before(time.Unix(findTimestamp, 0)) { lastSolvedTime = time.Unix(findTimestamp, 0) - go func() { targetIsu.StreamsForScenario.StateChan <- solvedCondition }() + targetIsu.StreamsForScenario.StateChan <- solvedCondition //バッファがあるのでブロック率は低い読みで直列に投げる } } } diff --git a/bench/scenario/posting.go b/bench/scenario/posting.go index 7342ee935..1082f1cbc 100644 --- a/bench/scenario/posting.go +++ b/bench/scenario/posting.go @@ -75,7 +75,7 @@ func (s *Scenario) keepPosting(ctx context.Context, step *isucandar.BenchmarkSte //TODO: 検証可能な生成方法にする //TODO: stateの適用タイミングをちゃんと考える - conditions := []*model.IsuCondition{} + conditions := []model.IsuCondition{} conditionsReq := []service.PostIsuConditionRequest{} conditionLevelWorst := model.ConditionLevelInfo for state.NextConditionTimestamp().Before(nowTimeStamp) { @@ -134,9 +134,7 @@ func (s *Scenario) keepPosting(ctx context.Context, step *isucandar.BenchmarkSte step.AddScore(ScorePostConditionCritical) } go func() { - for _, c := range conditions { - scenarioChan.ConditionChan <- c - } + scenarioChan.ConditionChan <- conditions }() }() } @@ -148,7 +146,7 @@ func (state *posterState) NextConditionTimestamp() time.Time { func (state *posterState) NextIsLatestTimestamp(nowTimeStamp time.Time) bool { return nowTimeStamp.Before(time.Unix(state.lastCondition.TimestampUnix, 0).Add(PostInterval * 2)) } -func (state *posterState) GenerateNextCondition(randEngine *rand.Rand, stateChange model.IsuStateChange) *model.IsuCondition { +func (state *posterState) GenerateNextCondition(randEngine *rand.Rand, stateChange model.IsuStateChange) model.IsuCondition { //乱数初期化(逆算できるように) timeStamp := state.NextConditionTimestamp() @@ -186,10 +184,10 @@ func (state *posterState) GenerateNextCondition(randEngine *rand.Rand, stateChan } //新しいConditionを生成 - var condition *model.IsuCondition + var condition model.IsuCondition if state.isuStateDelete { //削除された椅子のConditionは0点固定 - condition = &model.IsuCondition{ + condition = model.IsuCondition{ StateChange: model.IsuStateChangeDelete, IsSitting: true, IsDirty: true, @@ -201,7 +199,7 @@ func (state *posterState) GenerateNextCondition(randEngine *rand.Rand, stateChan } } else { //新しいConditionを生成 - condition = &model.IsuCondition{ + condition = model.IsuCondition{ StateChange: stateChange, IsSitting: state.lastCondition.IsSitting, IsDirty: lastConditionIsDirty, @@ -263,7 +261,7 @@ func (state *posterState) GenerateNextCondition(randEngine *rand.Rand, stateChan } //last更新 - state.lastCondition = *condition + state.lastCondition = condition return condition } From cad2ecaa5fd08304b9101ecac2c363750db5a658 Mon Sep 17 00:00:00 2001 From: Nagarei Date: Thu, 8 Jul 2021 12:28:37 +0900 Subject: [PATCH 06/43] fix(bench): isuCountMax --- bench/scenario/load.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bench/scenario/load.go b/bench/scenario/load.go index 6431c736f..40e3cba6e 100644 --- a/bench/scenario/load.go +++ b/bench/scenario/load.go @@ -103,13 +103,14 @@ scenarioLoop: step.AddScore(ScoreNormalUserLoop) //TODO: 得点条件の修正 //シナリオに成功している場合は椅子追加 - if isuCount < scenarioDoneCount/30 { + if isuCount < scenarioDoneCount/30 && isuCount < isuCountMax { isu := s.NewIsu(ctx, step, user, true) if isu == nil { logger.AdminLogger.Println("Normal User fail: NewIsu") } else { isuCount++ } + //logger.AdminLogger.Printf("Normal User Isu: %d\n", isuCount) } } scenarioSuccess = true From efd435cb2d9a9e720784811d302c9f752802ce53 Mon Sep 17 00:00:00 2001 From: ShotaKitazawa Date: Thu, 8 Jul 2021 15:47:29 +0900 Subject: [PATCH 07/43] =?UTF-8?q?feat(infra):=20=E3=82=A4=E3=83=B3?= =?UTF-8?q?=E3=82=B9=E3=82=BF=E3=83=B3=E3=82=B9=E5=88=9D=E5=9B=9E=E8=B5=B7?= =?UTF-8?q?=E5=8B=95=E6=99=82=E3=81=AB=20env.sh=20=E3=82=92=E7=94=9F?= =?UTF-8?q?=E6=88=90=E3=81=99=E3=82=8B=E3=82=B9=E3=82=AF=E3=83=AA=E3=83=97?= =?UTF-8?q?=E3=83=88=E3=81=AE=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ansible/roles/contestant/files/home/isucon/env.sh | 5 ----- .../lib/cloud/scripts/per-instance/generate-env.sh | 11 +++++++++++ .../ansible/roles/contestant/tasks/generate_env.yml | 9 +++++++++ .../ansible/roles/contestant/tasks/isucondition.yml | 10 ++-------- provisioning/packer/base.libsonnet | 2 +- 5 files changed, 23 insertions(+), 14 deletions(-) delete mode 100644 provisioning/ansible/roles/contestant/files/home/isucon/env.sh create mode 100644 provisioning/ansible/roles/contestant/files/var/lib/cloud/scripts/per-instance/generate-env.sh create mode 100644 provisioning/ansible/roles/contestant/tasks/generate_env.yml diff --git a/provisioning/ansible/roles/contestant/files/home/isucon/env.sh b/provisioning/ansible/roles/contestant/files/home/isucon/env.sh deleted file mode 100644 index 54760a70b..000000000 --- a/provisioning/ansible/roles/contestant/files/home/isucon/env.sh +++ /dev/null @@ -1,5 +0,0 @@ -MYSQL_HOST="127.0.0.1" -MYSQL_PORT=3306 -MYSQL_USER=isucon -MYSQL_DBNAME=isucondition -MYSQL_PASS=isucon diff --git a/provisioning/ansible/roles/contestant/files/var/lib/cloud/scripts/per-instance/generate-env.sh b/provisioning/ansible/roles/contestant/files/var/lib/cloud/scripts/per-instance/generate-env.sh new file mode 100644 index 000000000..3740b8edd --- /dev/null +++ b/provisioning/ansible/roles/contestant/files/var/lib/cloud/scripts/per-instance/generate-env.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +cat << _EOF_ > /home/isucon/env.sh +MYSQL_HOST="127.0.0.1" +MYSQL_PORT=3306 +MYSQL_USER=isucon +MYSQL_DBNAME=isucondition +MYSQL_PASS=isucon +ISU_CONDITION_IP="$(curl -s http://169.254.169.254/latest/meta-data/public-ipv4)" +_EOF_ +chown isucon: /home/isucon/env.sh diff --git a/provisioning/ansible/roles/contestant/tasks/generate_env.yml b/provisioning/ansible/roles/contestant/tasks/generate_env.yml new file mode 100644 index 000000000..9fb496837 --- /dev/null +++ b/provisioning/ansible/roles/contestant/tasks/generate_env.yml @@ -0,0 +1,9 @@ +--- +- name: "roles/contestant/tasks/generate_env: Deploy generate-env.sh" + tags: + - aws + become_user: root + copy: + src: "var/lib/cloud/scripts/per-instance/generate-env_aws.sh" + dest: "/var/lib/cloud/scripts/per-instance/generate-env.sh" + mode: "0755" diff --git a/provisioning/ansible/roles/contestant/tasks/isucondition.yml b/provisioning/ansible/roles/contestant/tasks/isucondition.yml index 8dab7c022..f408a4aba 100644 --- a/provisioning/ansible/roles/contestant/tasks/isucondition.yml +++ b/provisioning/ansible/roles/contestant/tasks/isucondition.yml @@ -8,14 +8,8 @@ owner: isucon group: isucon -- name: "roles/contestant/tasks/isucondition: Deploy env.sh" - become_user: isucon - copy: - src: "home/isucon/env.sh" - dest: "/home/isucon/env.sh" - owner: "isucon" - group: "isucon" - mode: "0644" +- name: "roles/contestant/tasks/isucondition: Include generate_env.yml" + include: generate_env.yml - name: "roles/contestant/tasks/isucondition: Include isucondition-frontend.yml" include: isucondition-frontend.yml diff --git a/provisioning/packer/base.libsonnet b/provisioning/packer/base.libsonnet index a9ea24238..d6414fc7a 100644 --- a/provisioning/packer/base.libsonnet +++ b/provisioning/packer/base.libsonnet @@ -156,7 +156,7 @@ run_ansible: { type: 'shell', inline: [ - '( cd /dev/shm/ansible && sudo ansible-playbook -u root -i hosts -t ' + $.arg_variant + ' site.yml )', + '( cd /dev/shm/ansible && sudo ansible-playbook -u root -i hosts -t aws -t ' + $.arg_variant + ' site.yml )', ], }, remove_ansible: { From 0e2031122e2e7a31bbee67e9dfa9f7145fc1946c Mon Sep 17 00:00:00 2001 From: Nagarei Date: Thu, 8 Jul 2021 18:33:07 +0900 Subject: [PATCH 08/43] feat(bench): IsuConditionIterator --- bench/model/isuCondition.go | 74 +++++++++++++++++++++++++++++++++++-- bench/scenario/posting.go | 8 ++-- 2 files changed, 76 insertions(+), 6 deletions(-) diff --git a/bench/model/isuCondition.go b/bench/model/isuCondition.go index 2bf0c6377..eeac8134e 100644 --- a/bench/model/isuCondition.go +++ b/bench/model/isuCondition.go @@ -4,9 +4,10 @@ package model type ConditionLevel int const ( - ConditionLevelInfo ConditionLevel = iota - ConditionLevelWarning - ConditionLevelCritical + ConditionLevelNone ConditionLevel = 0 + ConditionLevelInfo ConditionLevel = 1 + ConditionLevelWarning ConditionLevel = 2 + ConditionLevelCritical ConditionLevel = 4 ) //TODO: メモリ節約の必要があるなら考える @@ -20,5 +21,72 @@ type IsuCondition struct { IsBroken bool ConditionLevel ConditionLevel `json:"-"` Message string `json:"message"` + OwnerID string // Owner *Isu } + +//left < right +func (left *IsuCondition) Less(right *IsuCondition) bool { + return left.TimestampUnix < right.TimestampUnix && + (left.TimestampUnix == right.TimestampUnix && left.OwnerID < right.OwnerID) +} + +//conditionをcreated at順で見る +type IsuConditionArray struct { + Info []IsuCondition + Warning []IsuCondition + Critical []IsuCondition +} + +//conditionをcreated atの大きい順で見る +type IsuConditionIterator struct { + filter ConditionLevel + indexInfo int + indexWarning int + indexCritical int + parent *IsuConditionArray +} + +func (ia *IsuConditionArray) End(filter ConditionLevel) IsuConditionIterator { + return IsuConditionIterator{ + filter: filter, + indexInfo: len(ia.Info), + indexWarning: len(ia.Warning), + indexCritical: len(ia.Critical), + parent: ia, + } +} + +//return: nil:もう要素がない +func (iter *IsuConditionIterator) Prev() *IsuCondition { + maxType := ConditionLevelNone + var max *IsuCondition + if (iter.filter&ConditionLevelInfo) != 0 && iter.indexInfo != 0 { + if max == nil || max.Less(&iter.parent.Info[iter.indexInfo-1]) { + maxType = ConditionLevelInfo + max = &iter.parent.Info[iter.indexInfo-1] + } + } + if (iter.filter&ConditionLevelWarning) != 0 && iter.indexWarning != 0 { + if max == nil || max.Less(&iter.parent.Warning[iter.indexWarning-1]) { + maxType = ConditionLevelWarning + max = &iter.parent.Warning[iter.indexWarning-1] + } + } + if (iter.filter&ConditionLevelCritical) != 0 && iter.indexCritical != 0 { + if max == nil || max.Less(&iter.parent.Critical[iter.indexCritical-1]) { + maxType = ConditionLevelCritical + max = &iter.parent.Critical[iter.indexCritical-1] + } + } + + switch maxType { + case ConditionLevelInfo: + iter.indexInfo-- + case ConditionLevelWarning: + iter.indexWarning-- + case ConditionLevelCritical: + iter.indexCritical-- + } + return max +} diff --git a/bench/scenario/posting.go b/bench/scenario/posting.go index 1082f1cbc..52822bc26 100644 --- a/bench/scenario/posting.go +++ b/bench/scenario/posting.go @@ -80,8 +80,8 @@ func (s *Scenario) keepPosting(ctx context.Context, step *isucandar.BenchmarkSte conditionLevelWorst := model.ConditionLevelInfo for state.NextConditionTimestamp().Before(nowTimeStamp) { //次のstateを生成 - condition := state.GenerateNextCondition(randEngine, stateChange) //TODO: stateの適用タイミングをちゃんと考える - stateChange = model.IsuStateChangeNone //TODO: stateの適用タイミングをちゃんと考える + condition := state.GenerateNextCondition(randEngine, stateChange, jiaIsuUUID) //TODO: stateの適用タイミングをちゃんと考える + stateChange = model.IsuStateChangeNone //TODO: stateの適用タイミングをちゃんと考える if conditionLevelWorst < condition.ConditionLevel { conditionLevelWorst = condition.ConditionLevel } @@ -146,7 +146,7 @@ func (state *posterState) NextConditionTimestamp() time.Time { func (state *posterState) NextIsLatestTimestamp(nowTimeStamp time.Time) bool { return nowTimeStamp.Before(time.Unix(state.lastCondition.TimestampUnix, 0).Add(PostInterval * 2)) } -func (state *posterState) GenerateNextCondition(randEngine *rand.Rand, stateChange model.IsuStateChange) model.IsuCondition { +func (state *posterState) GenerateNextCondition(randEngine *rand.Rand, stateChange model.IsuStateChange, jiaIsuUUID string) model.IsuCondition { //乱数初期化(逆算できるように) timeStamp := state.NextConditionTimestamp() @@ -196,6 +196,7 @@ func (state *posterState) GenerateNextCondition(randEngine *rand.Rand, stateChan ConditionLevel: model.ConditionLevelCritical, Message: "", TimestampUnix: timeStamp.Unix(), + OwnerID: jiaIsuUUID, } } else { //新しいConditionを生成 @@ -208,6 +209,7 @@ func (state *posterState) GenerateNextCondition(randEngine *rand.Rand, stateChan //ConditionLevel: model.ConditionLevelCritical, Message: "", TimestampUnix: timeStamp.Unix(), + OwnerID: jiaIsuUUID, } //sitting if condition.IsSitting { From 718c781400a004789d978768532359c4cf4a83ed Mon Sep 17 00:00:00 2001 From: Nagarei Date: Thu, 8 Jul 2021 19:15:12 +0900 Subject: [PATCH 09/43] feat(bench): UpperBoundIsuConditionIndex --- bench/model/isuCondition.go | 65 +++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/bench/model/isuCondition.go b/bench/model/isuCondition.go index eeac8134e..bcb808233 100644 --- a/bench/model/isuCondition.go +++ b/bench/model/isuCondition.go @@ -31,6 +31,23 @@ func (left *IsuCondition) Less(right *IsuCondition) bool { (left.TimestampUnix == right.TimestampUnix && left.OwnerID < right.OwnerID) } +type IsuConditionCursor struct { + TimestampUnix int64 + OwnerID string +} + +//left < right +func (left *IsuCondition) Less2(right *IsuConditionCursor) bool { + return left.TimestampUnix < right.TimestampUnix && + (left.TimestampUnix == right.TimestampUnix && left.OwnerID < right.OwnerID) +} + +//left < right +func (left *IsuConditionCursor) Less2(right *IsuCondition) bool { + return left.TimestampUnix < right.TimestampUnix && + (left.TimestampUnix == right.TimestampUnix && left.OwnerID < right.OwnerID) +} + //conditionをcreated at順で見る type IsuConditionArray struct { Info []IsuCondition @@ -57,6 +74,18 @@ func (ia *IsuConditionArray) End(filter ConditionLevel) IsuConditionIterator { } } +func (iter *IsuConditionIterator) UpperBoundIsuConditionIndex(targetTimestamp int64, targetIsuUUID string) { + if (iter.filter & ConditionLevelInfo) != 0 { + iter.indexInfo = upperBoundIsuConditionIndex(iter.parent.Info, len(iter.parent.Info), targetTimestamp, targetIsuUUID) + } + if (iter.filter & ConditionLevelWarning) != 0 { + iter.indexWarning = upperBoundIsuConditionIndex(iter.parent.Warning, len(iter.parent.Warning), targetTimestamp, targetIsuUUID) + } + if (iter.filter & ConditionLevelCritical) != 0 { + iter.indexCritical = upperBoundIsuConditionIndex(iter.parent.Critical, len(iter.parent.Critical), targetTimestamp, targetIsuUUID) + } +} + //return: nil:もう要素がない func (iter *IsuConditionIterator) Prev() *IsuCondition { maxType := ConditionLevelNone @@ -90,3 +119,39 @@ func (iter *IsuConditionIterator) Prev() *IsuCondition { } return max } + +//baseはlessの昇順 +func upperBoundIsuConditionIndex(base []IsuCondition, end int, targetTimestamp int64, targetIsuUUID string) int { + //末尾の方にあることが分かっているので、末尾を固定要素ずつ線形探索 + 二分探索 + //assert end <= len(base) + target := IsuConditionCursor{TimestampUnix: targetTimestamp, OwnerID: targetIsuUUID} + if end <= 0 { + return end //要素が見つからない + } + //[0]が番兵になるかチェック + if target.Less2(&base[0]) { + return 0 //0がupperBound + } + + //線形探索 ngがbase[ng] <= targetになるまで探索 + const defaultRange = 64 + ok := end - 1 + ng := end - defaultRange + ng = (ng / defaultRange) * defaultRange //0未満になるのが嫌なので、defaultRangeの倍数にする + for target.Less2(&base[ng]) { //Timestampはunique仮定なので、<で良い(等価が見つかればそれで良し) + ok = ng + ng -= defaultRange + } + + //答えは(ng, ok]内にあるはずなので、二分探索 + for ok-ng > 1 { + mid := (ok + ng) / 2 + if target.Less2(&base[mid]) { + ok = mid + } else { + ng = mid + } + } + + return ok +} From 4b43852cccaf73464d31f8dfff93be17a23606ac Mon Sep 17 00:00:00 2001 From: Nagarei Date: Thu, 8 Jul 2021 22:05:26 +0900 Subject: [PATCH 10/43] feat(bench): WIP verifySingleIsuConditions --- bench/model/isuCondition.go | 6 ++++++ bench/scenario/error.go | 5 +++++ bench/scenario/verify.go | 40 +++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/bench/model/isuCondition.go b/bench/model/isuCondition.go index bcb808233..45cd958a3 100644 --- a/bench/model/isuCondition.go +++ b/bench/model/isuCondition.go @@ -36,6 +36,12 @@ type IsuConditionCursor struct { OwnerID string } +//left < right +func (left *IsuConditionCursor) Less(right *IsuConditionCursor) bool { + return left.TimestampUnix < right.TimestampUnix && + (left.TimestampUnix == right.TimestampUnix && left.OwnerID < right.OwnerID) +} + //left < right func (left *IsuCondition) Less2(right *IsuConditionCursor) bool { return left.TimestampUnix < right.TimestampUnix && diff --git a/bench/scenario/error.go b/bench/scenario/error.go index fd4417478..58097f195 100644 --- a/bench/scenario/error.go +++ b/bench/scenario/error.go @@ -119,6 +119,11 @@ func errorMissmatch(res *http.Response, message string, args ...interface{}) err return failure.NewError(ErrMissmatch, fmt.Errorf(message+": %d (%s: %s)", args...)) } +func errorInvalid(res *http.Response, message string, args ...interface{}) error { + args = append(args, res.StatusCode, res.Request.Method, res.Request.URL.Path) + return failure.NewError(ErrInvalid, fmt.Errorf(message+": %d (%s: %s)", args...)) +} + func errorBadResponse(res *http.Response, message string, args ...interface{}) error { args = append(args, res.StatusCode, res.Request.Method, res.Request.URL.Path) return failure.NewError(ErrBadResponse, fmt.Errorf(message+": %d (%s: %s)", args...)) diff --git a/bench/scenario/verify.go b/bench/scenario/verify.go index ba3a36243..b25259675 100644 --- a/bench/scenario/verify.go +++ b/bench/scenario/verify.go @@ -110,3 +110,43 @@ func verifyIsuOrderByCreatedAt(res *http.Response, expectedReverse []*model.Isu, // errs := []error{} // return errs // } + +// +//mustExistUntil: この値以下のtimestampを持つものは全て反映されているべき +func verifySingleIsuConditions(res *http.Response, base *model.IsuConditionArray, filter model.ConditionLevel, cursor model.IsuConditionCursor, backendData []service.GetIsuConditionResponse, mustExistUntil int64) error { + + //expectedの開始位置を探す() + baseIter := base.End(filter) + baseIter.UpperBoundIsuConditionIndex(cursor.TimestampUnix, cursor.OwnerID) + + //backendDataの先頭からチェック + lastSort := model.IsuConditionCursor{TimestampUnix: backendData[0].Timestamp + 1, OwnerID: ""} + for _, c := range backendData { + nowSort := model.IsuConditionCursor{TimestampUnix: c.Timestamp, OwnerID: c.JIAIsuUUID} + if !nowSort.Less(&lastSort) { + return errorInvalid(res, "整列順が正しくありません") + } + + var expected *model.IsuCondition + for { + expected = baseIter.Prev() + if expected == nil { + return errorMissmatch(res, "存在しないはずのデータが返されました") + } + + if expected.TimestampUnix == c.Timestamp { + break //ok + } + + if expected.TimestampUnix <= mustExistUntil { + return errorMissmatch(res, "データが足りません") + } + } + + //TODO: 等価チェック + + lastSort = nowSort + } + + return nil +} From b15c6040d060d46d548137a288f55622ed7bb635 Mon Sep 17 00:00:00 2001 From: ShotaKitazawa Date: Fri, 9 Jul 2021 09:56:59 +0900 Subject: [PATCH 11/43] =?UTF-8?q?feat(infra):=20=E3=82=B3=E3=83=A1?= =?UTF-8?q?=E3=83=B3=E3=83=88=E5=86=85=E5=AE=B9=E3=81=AE=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=20#296?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../scripts/per-instance/{generate-env.sh => generate-env_aws.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename provisioning/ansible/roles/contestant/files/var/lib/cloud/scripts/per-instance/{generate-env.sh => generate-env_aws.sh} (100%) diff --git a/provisioning/ansible/roles/contestant/files/var/lib/cloud/scripts/per-instance/generate-env.sh b/provisioning/ansible/roles/contestant/files/var/lib/cloud/scripts/per-instance/generate-env_aws.sh similarity index 100% rename from provisioning/ansible/roles/contestant/files/var/lib/cloud/scripts/per-instance/generate-env.sh rename to provisioning/ansible/roles/contestant/files/var/lib/cloud/scripts/per-instance/generate-env_aws.sh From 4624307d8e639ede1d01082bd7507a34acab6402 Mon Sep 17 00:00:00 2001 From: Nagarei Date: Fri, 9 Jul 2021 11:03:15 +0900 Subject: [PATCH 12/43] =?UTF-8?q?feat(bench):=20=E7=AD=89=E4=BE=A1?= =?UTF-8?q?=E3=83=81=E3=82=A7=E3=83=83=E3=82=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bench/scenario/verify.go | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/bench/scenario/verify.go b/bench/scenario/verify.go index b25259675..5b2f27e3f 100644 --- a/bench/scenario/verify.go +++ b/bench/scenario/verify.go @@ -7,6 +7,7 @@ package scenario import ( "encoding/json" + "fmt" "net/http" "strings" @@ -113,7 +114,7 @@ func verifyIsuOrderByCreatedAt(res *http.Response, expectedReverse []*model.Isu, // //mustExistUntil: この値以下のtimestampを持つものは全て反映されているべき -func verifySingleIsuConditions(res *http.Response, base *model.IsuConditionArray, filter model.ConditionLevel, cursor model.IsuConditionCursor, backendData []service.GetIsuConditionResponse, mustExistUntil int64) error { +func verifyIsuConditions(res *http.Response, base *model.IsuConditionArray, filter model.ConditionLevel, cursor model.IsuConditionCursor, isuMap map[string]*model.Isu, backendData []service.GetIsuConditionResponse, mustExistUntil int64) error { //expectedの開始位置を探す() baseIter := base.End(filter) @@ -143,7 +144,39 @@ func verifySingleIsuConditions(res *http.Response, base *model.IsuConditionArray } } - //TODO: 等価チェック + //等価チェック + expectedCondition := fmt.Sprintf("is_dirty=%v,is_overweight=%v,is_broken=%v", + expected.IsDirty, + expected.IsOverweight, + expected.IsBroken, + ) + var expectedConditionLevelStr string + warnCount := 0 + if expected.IsDirty { + warnCount++ + } + if expected.IsOverweight { + warnCount++ + } + if expected.IsBroken { + warnCount++ + } + switch warnCount { + case 0: + expectedConditionLevelStr = "info" + case 1, 2: + expectedConditionLevelStr = "warning" + case 3: + expectedConditionLevelStr = "critical" + } + if c.Condition != expectedCondition || + c.ConditionLevel != expectedConditionLevelStr || + c.IsSitting != expected.IsSitting || + c.JIAIsuUUID != expected.OwnerID || + c.Message != expected.Message || + c.IsuName != isuMap[expected.OwnerID].Name { + return errorMissmatch(res, "データが正しくありません") + } lastSort = nowSort } From ccb8ae38167effc2776b9d3bae23c5e2dff9ac3e Mon Sep 17 00:00:00 2001 From: Nagarei Date: Fri, 9 Jul 2021 11:31:47 +0900 Subject: [PATCH 13/43] =?UTF-8?q?feat(bench):=20condition/isu=E3=81=AE?= =?UTF-8?q?=E6=A4=9C=E8=A8=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bench/model/isu.go | 4 +-- bench/model/isuCondition.go | 19 +++++++++++++ bench/scenario/action.go | 3 ++- bench/scenario/load.go | 54 +++++++++++++++++++++++++++---------- bench/scenario/verify.go | 4 ++- 5 files changed, 66 insertions(+), 18 deletions(-) diff --git a/bench/model/isu.go b/bench/model/isu.go index 20d734de7..9bfdaa367 100644 --- a/bench/model/isu.go +++ b/bench/model/isu.go @@ -45,7 +45,7 @@ type Isu struct { IsWantDeactivated bool //シナリオ上でDeleteリクエストを送ったかどうか isDeactivated bool //実際にdeactivateされているか StreamsForScenario *StreamsForScenario //posterスレッドとの通信 - Conditions []IsuCondition //シナリオスレッドからのみ参照 + Conditions IsuConditionArray //シナリオスレッドからのみ参照 } //新しいISUの生成 @@ -74,7 +74,7 @@ func NewRandomIsuRaw(owner *User) (*Isu, *StreamsForPoster, error) { StateChan: stateChan, ConditionChan: conditionChan, }, - Conditions: []IsuCondition{}, + Conditions: NewIsuConditionArray(), } streamsForPoster := &StreamsForPoster{ diff --git a/bench/model/isuCondition.go b/bench/model/isuCondition.go index 45cd958a3..fa1e979b1 100644 --- a/bench/model/isuCondition.go +++ b/bench/model/isuCondition.go @@ -70,6 +70,25 @@ type IsuConditionIterator struct { parent *IsuConditionArray } +func NewIsuConditionArray() IsuConditionArray { + return IsuConditionArray{ + Info: []IsuCondition{}, + Warning: []IsuCondition{}, + Critical: []IsuCondition{}, + } +} + +func (ia *IsuConditionArray) Add(cond *IsuCondition) { + switch cond.ConditionLevel { + case ConditionLevelInfo: + ia.Info = append(ia.Info, *cond) + case ConditionLevelWarning: + ia.Warning = append(ia.Warning, *cond) + case ConditionLevelCritical: + ia.Critical = append(ia.Critical, *cond) + } +} + func (ia *IsuConditionArray) End(filter ConditionLevel) IsuConditionIterator { return IsuConditionIterator{ filter: filter, diff --git a/bench/scenario/action.go b/bench/scenario/action.go index e193e0edf..830766dc3 100644 --- a/bench/scenario/action.go +++ b/bench/scenario/action.go @@ -601,6 +601,7 @@ func getIsuGraphErrorAction(ctx context.Context, a *agent.Agent, id string, date } func browserGetHomeAction(ctx context.Context, a *agent.Agent, + virtualNowUnix int64, validateIsu func(*http.Response, []*service.Isu) []error, validateCondition func(*http.Response, []*service.GetIsuConditionResponse) []error, ) ([]*service.Isu, []*service.GetIsuConditionResponse, []error) { @@ -624,7 +625,7 @@ func browserGetHomeAction(ctx context.Context, a *agent.Agent, errors = append(errors, validateIsu(hres, isuList)...) } - conditions, hres, err := getConditionAction(ctx, a, service.GetIsuConditionRequest{CursorEndTime: uint64(time.Now().Unix()), CursorJIAIsuUUID: "z", ConditionLevel: "critical,warning,info"}) + conditions, hres, err := getConditionAction(ctx, a, service.GetIsuConditionRequest{CursorEndTime: uint64(virtualNowUnix), CursorJIAIsuUUID: "z", ConditionLevel: "critical,warning,info"}) if err != nil { errors = append(errors, err) } else { diff --git a/bench/scenario/load.go b/bench/scenario/load.go index 40e3cba6e..6ac7bc86e 100644 --- a/bench/scenario/load.go +++ b/bench/scenario/load.go @@ -126,7 +126,9 @@ scenarioLoop: if !ok { break getConditionFromPosterLoop } - isu.Conditions = append(isu.Conditions, conditions...) + for _, c := range conditions { + isu.Conditions.Add(&c) + } default: break getConditionFromPosterLoop } @@ -139,7 +141,9 @@ scenarioLoop: targetIsu := user.IsuListOrderByCreatedAt[nextTargetIsuIndex] //GET / - _, _, errs := browserGetHomeAction(ctx, user.Agent, + realNow := time.Now() + virtualNow := s.ToVirtualTime(realNow) + _, _, errs := browserGetHomeAction(ctx, user.Agent, virtualNow.Unix(), func(res *http.Response, isuList []*service.Isu) []error { return verifyIsuOrderByCreatedAt(res, user.IsuListOrderByCreatedAt, isuList) }, @@ -171,7 +175,8 @@ scenarioLoop: //TODO: リロード //定期的にconditionを見に行くシナリオ - virtualNow := s.ToVirtualTime(time.Now()) + realNow = time.Now() + virtualNow = s.ToVirtualTime(realNow) _, conditions, errs := browserGetIsuConditionAction(ctx, user.Agent, targetIsu.JIAIsuUUID, service.GetIsuConditionRequest{ StartTime: nil, @@ -181,6 +186,14 @@ scenarioLoop: Limit: nil, }, func(res *http.Response, conditions []*service.GetIsuConditionResponse) []error { + //conditionの検証 + err := verifyIsuConditions(res, &targetIsu.Conditions, model.ConditionLevelInfo|model.ConditionLevelWarning|model.ConditionLevelCritical, + model.IsuConditionCursor{TimestampUnix: virtualNow.Unix(), OwnerID: targetIsu.JIAIsuUUID}, targetIsu.Owner.IsuListByID, + conditions, s.ToVirtualTime(realNow.Add(-1*time.Second)).Unix(), + ) + if err != nil { + return []error{err} + } return []error{} }, ) @@ -193,13 +206,13 @@ scenarioLoop: } //スクロール - var res *http.Response for i := 0; i < 2 && len(conditions) == 20*(i+1); i++ { var conditionsTmp []*service.GetIsuConditionResponse - conditionsTmp, res, err = getIsuConditionAction(ctx, user.Agent, targetIsu.JIAIsuUUID, + CursorEndTime := conditions[len(conditions)-1].Timestamp + conditionsTmp, res, err := getIsuConditionAction(ctx, user.Agent, targetIsu.JIAIsuUUID, service.GetIsuConditionRequest{ StartTime: nil, - CursorEndTime: uint64(conditions[len(conditions)-1].Timestamp), + CursorEndTime: uint64(CursorEndTime), CursorJIAIsuUUID: "", ConditionLevel: "info,warning,critical", Limit: nil, @@ -209,13 +222,19 @@ scenarioLoop: scenarioSuccess = false step.AddError(err) break - } else { - conditions = append(conditions, conditionsTmp...) } - } + //検証 + err = verifyIsuConditions(res, &targetIsu.Conditions, model.ConditionLevelInfo|model.ConditionLevelWarning|model.ConditionLevelCritical, + model.IsuConditionCursor{TimestampUnix: CursorEndTime, OwnerID: targetIsu.JIAIsuUUID}, targetIsu.Owner.IsuListByID, + conditions, s.ToVirtualTime(realNow.Add(-1*time.Second)).Unix(), + ) + if err != nil { + scenarioSuccess = false + step.AddError(err) + break + } - //TODO: conditionの検証 - if res != nil { //エラーつぶし + conditions = append(conditions, conditionsTmp...) } //conditionを確認して、椅子状態を改善 @@ -240,7 +259,8 @@ scenarioLoop: } else { //TODO: graphを見に行くシナリオ - virtualNow := s.ToVirtualTime(time.Now()) + realNow = time.Now() + virtualNow = s.ToVirtualTime(realNow) virtualToday := time.Date(virtualNow.Year(), virtualNow.Month(), virtualNow.Day(), 0, 0, 0, 0, virtualNow.Location()) _, graphToday, errs := browserGetIsuGraphAction(ctx, user.Agent, targetIsu.JIAIsuUUID, uint64(virtualToday.Unix()), func(res *http.Response, graph []*service.GraphResponse) []error { @@ -285,12 +305,18 @@ scenarioLoop: StartTime: &startTime, CursorEndTime: uint64(errorEndAtUnix), CursorJIAIsuUUID: "", - ConditionLevel: "info,warning,critical", + ConditionLevel: "warning,critical", Limit: nil, }, func(res *http.Response, conditions []*service.GetIsuConditionResponse) []error { + err := verifyIsuConditions(res, &targetIsu.Conditions, model.ConditionLevelWarning|model.ConditionLevelCritical, + model.IsuConditionCursor{TimestampUnix: errorEndAtUnix, OwnerID: targetIsu.JIAIsuUUID}, targetIsu.Owner.IsuListByID, + conditions, s.ToVirtualTime(realNow.Add(-1*time.Second)).Unix(), + ) + if err != nil { + return []error{err} + } return []error{} - //TODO: 検証 }, ) for _, err := range errs { diff --git a/bench/scenario/verify.go b/bench/scenario/verify.go index 5b2f27e3f..ad8e0382c 100644 --- a/bench/scenario/verify.go +++ b/bench/scenario/verify.go @@ -114,7 +114,9 @@ func verifyIsuOrderByCreatedAt(res *http.Response, expectedReverse []*model.Isu, // //mustExistUntil: この値以下のtimestampを持つものは全て反映されているべき -func verifyIsuConditions(res *http.Response, base *model.IsuConditionArray, filter model.ConditionLevel, cursor model.IsuConditionCursor, isuMap map[string]*model.Isu, backendData []service.GetIsuConditionResponse, mustExistUntil int64) error { +func verifyIsuConditions(res *http.Response, + base *model.IsuConditionArray, filter model.ConditionLevel, cursor model.IsuConditionCursor, isuMap map[string]*model.Isu, + backendData []*service.GetIsuConditionResponse, mustExistUntil int64) error { //expectedの開始位置を探す() baseIter := base.End(filter) From 7b11f9b503218da9cf7eead0cc5cc903f824f030 Mon Sep 17 00:00:00 2001 From: Nagarei Date: Fri, 9 Jul 2021 11:32:44 +0900 Subject: [PATCH 14/43] =?UTF-8?q?fix(bench):=20Error=20count=20over?= =?UTF-8?q?=E3=81=99=E3=82=8B=E5=89=8D=E3=81=AB=E3=83=99=E3=83=B3=E3=83=81?= =?UTF-8?q?=E3=81=8C=E6=AD=A2=E3=81=BE=E3=81=A3=E3=81=A6=E3=81=84=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bench/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/main.go b/bench/main.go index 700b4e2de..b7ef8db17 100644 --- a/bench/main.go +++ b/bench/main.go @@ -245,7 +245,7 @@ func main() { critical, _, deduction := checkError(err) - if critical || (deduction && atomic.AddInt64(&errorCount, 1) >= FAIL_ERROR_COUNT) { + if critical || (deduction && atomic.AddInt64(&errorCount, 1) > FAIL_ERROR_COUNT) { step.Cancel() } From 98b5fa850b16e27bde39ed44c10d84122a533e73 Mon Sep 17 00:00:00 2001 From: Nagarei Date: Fri, 9 Jul 2021 11:36:21 +0900 Subject: [PATCH 15/43] =?UTF-8?q?fix(bench):=20less=E3=81=AE=E3=83=90?= =?UTF-8?q?=E3=82=B0=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bench/model/isuCondition.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bench/model/isuCondition.go b/bench/model/isuCondition.go index fa1e979b1..e89b5915b 100644 --- a/bench/model/isuCondition.go +++ b/bench/model/isuCondition.go @@ -27,7 +27,7 @@ type IsuCondition struct { //left < right func (left *IsuCondition) Less(right *IsuCondition) bool { - return left.TimestampUnix < right.TimestampUnix && + return left.TimestampUnix < right.TimestampUnix || (left.TimestampUnix == right.TimestampUnix && left.OwnerID < right.OwnerID) } @@ -38,19 +38,19 @@ type IsuConditionCursor struct { //left < right func (left *IsuConditionCursor) Less(right *IsuConditionCursor) bool { - return left.TimestampUnix < right.TimestampUnix && + return left.TimestampUnix < right.TimestampUnix || (left.TimestampUnix == right.TimestampUnix && left.OwnerID < right.OwnerID) } //left < right func (left *IsuCondition) Less2(right *IsuConditionCursor) bool { - return left.TimestampUnix < right.TimestampUnix && + return left.TimestampUnix < right.TimestampUnix || (left.TimestampUnix == right.TimestampUnix && left.OwnerID < right.OwnerID) } //left < right func (left *IsuConditionCursor) Less2(right *IsuCondition) bool { - return left.TimestampUnix < right.TimestampUnix && + return left.TimestampUnix < right.TimestampUnix || (left.TimestampUnix == right.TimestampUnix && left.OwnerID < right.OwnerID) } From f6ca92944203a924965971e858ea754db8433c5b Mon Sep 17 00:00:00 2001 From: ShotaKitazawa Date: Fri, 9 Jul 2021 11:44:44 +0900 Subject: [PATCH 16/43] =?UTF-8?q?fix(infra):=20packer=20build=20=E6=99=82?= =?UTF-8?q?=E3=81=AB=20isucondition.go=20=E3=82=92=E8=B5=B7=E5=8B=95?= =?UTF-8?q?=E3=81=9B=E3=81=9A=20enable=20=E3=81=A0=E3=81=91=E3=81=99?= =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- provisioning/ansible/roles/contestant/tasks/isucondition.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/provisioning/ansible/roles/contestant/tasks/isucondition.yml b/provisioning/ansible/roles/contestant/tasks/isucondition.yml index f408a4aba..99fa84279 100644 --- a/provisioning/ansible/roles/contestant/tasks/isucondition.yml +++ b/provisioning/ansible/roles/contestant/tasks/isucondition.yml @@ -24,7 +24,6 @@ systemd: daemon_reload: "yes" name: "isucondition.go.service" - state: "restarted" enabled: "yes" - name: "roles.contestant.tasks.isucondition: Deploy isucon11 initial-data" From e9016597d18a977dab3dc9cf702373605ded72ed Mon Sep 17 00:00:00 2001 From: Nagarei Date: Fri, 9 Jul 2021 11:57:44 +0900 Subject: [PATCH 17/43] =?UTF-8?q?fix(bench):=20=E4=BA=8C=E5=88=86=E6=8E=A2?= =?UTF-8?q?=E7=B4=A2=E3=81=AE=E3=83=90=E3=82=B0=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bench/model/isuCondition.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/model/isuCondition.go b/bench/model/isuCondition.go index e89b5915b..b4e0ab06e 100644 --- a/bench/model/isuCondition.go +++ b/bench/model/isuCondition.go @@ -160,7 +160,7 @@ func upperBoundIsuConditionIndex(base []IsuCondition, end int, targetTimestamp i //線形探索 ngがbase[ng] <= targetになるまで探索 const defaultRange = 64 - ok := end - 1 + ok := end ng := end - defaultRange ng = (ng / defaultRange) * defaultRange //0未満になるのが嫌なので、defaultRangeの倍数にする for target.Less2(&base[ng]) { //Timestampはunique仮定なので、<で良い(等価が見つかればそれで良し) From e0079689970a096a991cd37970d982ce7f25060c Mon Sep 17 00:00:00 2001 From: ShotaKitazawa Date: Fri, 9 Jul 2021 11:57:58 +0900 Subject: [PATCH 18/43] fix(infra): fix ansible --- .../{jiaapi_standalone.service => jiaapi-standalone.service} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename provisioning/ansible/roles/contestant/files/etc/systemd/system/{jiaapi_standalone.service => jiaapi-standalone.service} (100%) diff --git a/provisioning/ansible/roles/contestant/files/etc/systemd/system/jiaapi_standalone.service b/provisioning/ansible/roles/contestant/files/etc/systemd/system/jiaapi-standalone.service similarity index 100% rename from provisioning/ansible/roles/contestant/files/etc/systemd/system/jiaapi_standalone.service rename to provisioning/ansible/roles/contestant/files/etc/systemd/system/jiaapi-standalone.service From 23be0f135bfc625d53610e6e65b65102b21b4c4a Mon Sep 17 00:00:00 2001 From: Nagarei Date: Fri, 9 Jul 2021 12:12:55 +0900 Subject: [PATCH 19/43] =?UTF-8?q?fix(bench):=20getConditionFromChan?= =?UTF-8?q?=E5=88=87=E3=82=8A=E5=87=BA=E3=81=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bench/scenario/load.go | 45 +++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/bench/scenario/load.go b/bench/scenario/load.go index 6ac7bc86e..d2606c4b5 100644 --- a/bench/scenario/load.go +++ b/bench/scenario/load.go @@ -117,22 +117,12 @@ scenarioLoop: //posterからconditionの取得 for _, isu := range user.IsuListOrderByCreatedAt { - getConditionFromPosterLoop: - for { - select { - case <-ctx.Done(): - return - case conditions, ok := <-isu.StreamsForScenario.ConditionChan: - if !ok { - break getConditionFromPosterLoop - } - for _, c := range conditions { - isu.Conditions.Add(&c) - } - default: - break getConditionFromPosterLoop - } - } + getConditionFromChan(ctx, isu, nil) //TODO: userConditionBuffer + } + select { + case <-ctx.Done(): + return + default: } //TODO: 乱数にする @@ -338,6 +328,29 @@ scenarioLoop: } } +func getConditionFromChan(ctx context.Context, isu *model.Isu, userConditionBuffer *model.IsuConditionArray) { + for { + select { + case <-ctx.Done(): + return + case conditions, ok := <-isu.StreamsForScenario.ConditionChan: + if !ok { + return + } + for _, c := range conditions { + isu.Conditions.Add(&c) + } + if userConditionBuffer != nil { + for _, c := range conditions { + userConditionBuffer.Add(&c) + } + } + default: + return + } + } +} + func findBadIsuState(conditions []*service.GetIsuConditionResponse) (model.IsuStateChange, int64) { //TODO: すでに改善済みのものを弾く From b33651a3a7affd28bee8df9630f5cc164a8f0829 Mon Sep 17 00:00:00 2001 From: Nagarei Date: Fri, 9 Jul 2021 12:15:51 +0900 Subject: [PATCH 20/43] =?UTF-8?q?=E6=A4=9C=E8=A8=BC=E5=89=8D=E3=81=AB?= =?UTF-8?q?=E3=83=87=E3=83=BC=E3=82=BF=E5=8F=96=E5=BE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bench/scenario/load.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/bench/scenario/load.go b/bench/scenario/load.go index d2606c4b5..164a36efc 100644 --- a/bench/scenario/load.go +++ b/bench/scenario/load.go @@ -138,6 +138,8 @@ scenarioLoop: return verifyIsuOrderByCreatedAt(res, user.IsuListOrderByCreatedAt, isuList) }, func(res *http.Response, conditions []*service.GetIsuConditionResponse) []error { + //検証前にデータ取得 + getConditionFromChan(ctx, targetIsu, nil) //TODO: userConditionBuffer //TODO: conditionの検証 return []error{} }, @@ -176,6 +178,8 @@ scenarioLoop: Limit: nil, }, func(res *http.Response, conditions []*service.GetIsuConditionResponse) []error { + //検証前にデータ取得 + getConditionFromChan(ctx, targetIsu, nil) //TODO: userConditionBuffer //conditionの検証 err := verifyIsuConditions(res, &targetIsu.Conditions, model.ConditionLevelInfo|model.ConditionLevelWarning|model.ConditionLevelCritical, model.IsuConditionCursor{TimestampUnix: virtualNow.Unix(), OwnerID: targetIsu.JIAIsuUUID}, targetIsu.Owner.IsuListByID, @@ -214,6 +218,7 @@ scenarioLoop: break } //検証 + //ここは、古いデータのはずなのでconditionのchanからの再取得は要らない err = verifyIsuConditions(res, &targetIsu.Conditions, model.ConditionLevelInfo|model.ConditionLevelWarning|model.ConditionLevelCritical, model.IsuConditionCursor{TimestampUnix: CursorEndTime, OwnerID: targetIsu.JIAIsuUUID}, targetIsu.Owner.IsuListByID, conditions, s.ToVirtualTime(realNow.Add(-1*time.Second)).Unix(), @@ -254,7 +259,9 @@ scenarioLoop: virtualToday := time.Date(virtualNow.Year(), virtualNow.Month(), virtualNow.Day(), 0, 0, 0, 0, virtualNow.Location()) _, graphToday, errs := browserGetIsuGraphAction(ctx, user.Agent, targetIsu.JIAIsuUUID, uint64(virtualToday.Unix()), func(res *http.Response, graph []*service.GraphResponse) []error { - return []error{} //TODO: 検証 + //検証前にデータ取得 + getConditionFromChan(ctx, targetIsu, nil) //TODO: userConditionBuffer + return []error{} //TODO: 検証 }, ) for _, err := range errs { @@ -299,6 +306,8 @@ scenarioLoop: Limit: nil, }, func(res *http.Response, conditions []*service.GetIsuConditionResponse) []error { + //検証 + //ここは、古いデータのはずなのでconditionのchanからの再取得は要らない err := verifyIsuConditions(res, &targetIsu.Conditions, model.ConditionLevelWarning|model.ConditionLevelCritical, model.IsuConditionCursor{TimestampUnix: errorEndAtUnix, OwnerID: targetIsu.JIAIsuUUID}, targetIsu.Owner.IsuListByID, conditions, s.ToVirtualTime(realNow.Add(-1*time.Second)).Unix(), From b9fe0533acb4742362a3568774107aa61f98b730 Mon Sep 17 00:00:00 2001 From: ShotaKitazawa Date: Fri, 9 Jul 2021 12:34:21 +0900 Subject: [PATCH 21/43] fix(ci): remove unneccesary code --- .github/workflows/packer.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/packer.yml b/.github/workflows/packer.yml index 308ddbdbe..f817912f8 100644 --- a/.github/workflows/packer.yml +++ b/.github/workflows/packer.yml @@ -102,12 +102,3 @@ jobs: run: | export PATH=${HOME}/work/_tool/isucon11-qualify:${PATH} make build-bench - - - uses: actions/upload-artifact@v2 - with: - name: manifest-amd64-contestant.json - path: provisioning/packer/output/manifest-amd64-contestant.json - - uses: actions/upload-artifact@v2 - with: - name: manifest-amd64-bench.json - path: provisioning/packer/output/manifest-amd64-bench.json From eb766c291b89d26cb8c4fe9729cb9b5d7d5ed056 Mon Sep 17 00:00:00 2001 From: ShotaKitazawa Date: Fri, 9 Jul 2021 13:15:27 +0900 Subject: [PATCH 22/43] =?UTF-8?q?feat(infra):=20packer=20build=20=E3=81=97?= =?UTF-8?q?=E3=81=9F=20AMI=20=E3=81=AB=20'GitTag:=20git=E3=82=BF=E3=82=B0?= =?UTF-8?q?=E5=90=8D'=20=E3=81=A8=E3=81=AA=E3=82=8B=20tag=20=E3=82=92?= =?UTF-8?q?=E4=BB=98=E4=B8=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/packer.yml | 7 +++++++ provisioning/packer/base.libsonnet | 12 ++---------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/.github/workflows/packer.yml b/.github/workflows/packer.yml index 308ddbdbe..92dcce329 100644 --- a/.github/workflows/packer.yml +++ b/.github/workflows/packer.yml @@ -71,6 +71,9 @@ jobs: working-directory: provisioning/packer steps: - uses: actions/checkout@v2 + - name: Get source tag of git + id: get_source_tag + run: echo ::set-output name=SOURCE_TAG::${GITHUB_REF#refs/tags/} - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v1 @@ -95,10 +98,14 @@ jobs: - run: make clean-output - name: "make build-contestant" + env: + GIT_TAG: ${{ steps.get_source_tag.outputs.SOURCE_TAG }} run: | export PATH=${HOME}/work/_tool/isucon11-qualify:${PATH} make build-contestant - name: "make build-bench" + env: + GIT_TAG: ${{ steps.get_source_tag.outputs.SOURCE_TAG }} run: | export PATH=${HOME}/work/_tool/isucon11-qualify:${PATH} make build-bench diff --git a/provisioning/packer/base.libsonnet b/provisioning/packer/base.libsonnet index d6414fc7a..93aa6ead5 100644 --- a/provisioning/packer/base.libsonnet +++ b/provisioning/packer/base.libsonnet @@ -10,6 +10,7 @@ aws_access_key: "{{env `AWS_ACCESS_KEY_ID`}}", aws_secret_key: "{{env `AWS_SECRET_ACCESS_KEY`}}", aws_session_token: "{{env `AWS_SESSION_TOKEN`}}", + git_tag: "{{env `GIT_TAG`}}", }, builder_ec2:: { @@ -35,6 +36,7 @@ Packer: '1', Family: 'isucon11q-' + $.arg_arch + '-' + $.arg_variant, Project: 'qualify-dev', + GitTag: '{{user "git_tag"}}' }, // TODO: spot instance を利用する @@ -55,16 +57,6 @@ ssh_interface: 'public_ip', associate_public_ip_address: true, - //vpc_id: 'vpc-0ee05560be5a92944', - // subnet_filter: { - // filters: { - // 'vpc-id': 'vpc-0ee05560be5a92944', - // 'tag:Tier': 'public', - // 'availability-zone': 'ap-northeast-1c', - // }, - // random: true, - // }, - run_tags: { Name: 'packer-isucon11q-' + $.arg_arch + '-' + $.arg_variant, Project: 'qualify-dev', From 7101eaad9aa03d380641b83e862edacfb1f56d1b Mon Sep 17 00:00:00 2001 From: ShotaKitazawa Date: Fri, 9 Jul 2021 13:52:05 +0900 Subject: [PATCH 23/43] feat(infra): remove nginx in bench --- provisioning/ansible/roles/common/tasks/package.yml | 1 - .../ansible/roles/contestant/tasks/isucondition-frontend.yml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/provisioning/ansible/roles/common/tasks/package.yml b/provisioning/ansible/roles/common/tasks/package.yml index b09628c3f..d273dc21b 100644 --- a/provisioning/ansible/roles/common/tasks/package.yml +++ b/provisioning/ansible/roles/common/tasks/package.yml @@ -22,7 +22,6 @@ - autoconf - automake - build-essential - - nginx - libxml2-dev - libsqlite3-dev - libbz2-dev diff --git a/provisioning/ansible/roles/contestant/tasks/isucondition-frontend.yml b/provisioning/ansible/roles/contestant/tasks/isucondition-frontend.yml index 8ce96eccd..a5fd6448f 100644 --- a/provisioning/ansible/roles/contestant/tasks/isucondition-frontend.yml +++ b/provisioning/ansible/roles/contestant/tasks/isucondition-frontend.yml @@ -15,7 +15,7 @@ PATH: "/home/isucon/local/node/bin:{{ ansible_env.PATH }}" command: npm run build -- name: Deploy static files +- name: "roles/contestant/tasks/isucondition-frontend: Deploy static files" become_user: root shell: | mkdir -p /www/data && cp -pR /home/isucon/webapp/frontend/dist/* /www/data/ From c113c9886f541e51cb649fc4289e45739e0a254e Mon Sep 17 00:00:00 2001 From: Nagarei Date: Fri, 9 Jul 2021 14:36:15 +0900 Subject: [PATCH 24/43] fix(bench): fix url param --- bench/scenario/action.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bench/scenario/action.go b/bench/scenario/action.go index 830766dc3..78f874d0b 100644 --- a/bench/scenario/action.go +++ b/bench/scenario/action.go @@ -519,7 +519,7 @@ func postIsuConditionErrorAction(ctx context.Context, a *agent.Agent, id string, } func getIsuConditionAction(ctx context.Context, a *agent.Agent, id string, req service.GetIsuConditionRequest) ([]*service.GetIsuConditionResponse, *http.Response, error) { - reqUrl := getIsuConditionRequestParams(fmt.Sprintf("/api/condition/%s?", id), req) + reqUrl := getIsuConditionRequestParams(fmt.Sprintf("/api/condition/%s", id), req) conditions := []*service.GetIsuConditionResponse{} res, err := reqJSONResJSON(ctx, a, http.MethodGet, reqUrl, nil, &conditions, []int{http.StatusOK}) if err != nil { @@ -529,7 +529,7 @@ func getIsuConditionAction(ctx context.Context, a *agent.Agent, id string, req s } func getIsuConditionErrorAction(ctx context.Context, a *agent.Agent, id string, req service.GetIsuConditionRequest) (string, *http.Response, error) { - reqUrl := getIsuConditionRequestParams(fmt.Sprintf("/api/condition/%s?", id), req) + reqUrl := getIsuConditionRequestParams(fmt.Sprintf("/api/condition/%s", id), req) res, text, err := reqNoContentResError(ctx, a, http.MethodGet, reqUrl, []int{http.StatusNotFound, http.StatusUnauthorized}) if err != nil { return "", nil, err @@ -538,7 +538,7 @@ func getIsuConditionErrorAction(ctx context.Context, a *agent.Agent, id string, } func getConditionAction(ctx context.Context, a *agent.Agent, req service.GetIsuConditionRequest) ([]*service.GetIsuConditionResponse, *http.Response, error) { - reqUrl := getIsuConditionRequestParams("/api/condition?", req) + reqUrl := getIsuConditionRequestParams("/api/condition", req) conditions := []*service.GetIsuConditionResponse{} res, err := reqJSONResJSON(ctx, a, http.MethodGet, reqUrl, nil, &conditions, []int{http.StatusOK}) if err != nil { @@ -548,7 +548,7 @@ func getConditionAction(ctx context.Context, a *agent.Agent, req service.GetIsuC } func getConditionErrorAction(ctx context.Context, a *agent.Agent, req service.GetIsuConditionRequest) (string, *http.Response, error) { - reqUrl := getIsuConditionRequestParams("/api/condition?", req) + reqUrl := getIsuConditionRequestParams("/api/condition", req) res, text, err := reqNoContentResError(ctx, a, http.MethodGet, reqUrl, []int{http.StatusNotFound, http.StatusUnauthorized}) if err != nil { return "", nil, err From f75e228d3950beaa8eb23055f841ba7ed876a320 Mon Sep 17 00:00:00 2001 From: Nagarei Date: Fri, 9 Jul 2021 14:42:47 +0900 Subject: [PATCH 25/43] =?UTF-8?q?fix(bench):=20=E5=A2=83=E7=95=8C=E6=9D=A1?= =?UTF-8?q?=E4=BB=B6=E3=83=90=E3=82=B0=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bench/model/isuCondition.go | 48 +++++++++++++++++++++++++++++++++++++ bench/scenario/verify.go | 12 +++++++--- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/bench/model/isuCondition.go b/bench/model/isuCondition.go index b4e0ab06e..09f243f9f 100644 --- a/bench/model/isuCondition.go +++ b/bench/model/isuCondition.go @@ -111,6 +111,18 @@ func (iter *IsuConditionIterator) UpperBoundIsuConditionIndex(targetTimestamp in } } +func (iter *IsuConditionIterator) LowerBoundIsuConditionIndex(targetTimestamp int64, targetIsuUUID string) { + if (iter.filter & ConditionLevelInfo) != 0 { + iter.indexInfo = lowerBoundIsuConditionIndex(iter.parent.Info, len(iter.parent.Info), targetTimestamp, targetIsuUUID) + } + if (iter.filter & ConditionLevelWarning) != 0 { + iter.indexWarning = lowerBoundIsuConditionIndex(iter.parent.Warning, len(iter.parent.Warning), targetTimestamp, targetIsuUUID) + } + if (iter.filter & ConditionLevelCritical) != 0 { + iter.indexCritical = lowerBoundIsuConditionIndex(iter.parent.Critical, len(iter.parent.Critical), targetTimestamp, targetIsuUUID) + } +} + //return: nil:もう要素がない func (iter *IsuConditionIterator) Prev() *IsuCondition { maxType := ConditionLevelNone @@ -180,3 +192,39 @@ func upperBoundIsuConditionIndex(base []IsuCondition, end int, targetTimestamp i return ok } + +//baseはlessの昇順 +func lowerBoundIsuConditionIndex(base []IsuCondition, end int, targetTimestamp int64, targetIsuUUID string) int { + //末尾の方にあることが分かっているので、末尾を固定要素ずつ線形探索 + 二分探索 + //assert end <= len(base) + target := IsuConditionCursor{TimestampUnix: targetTimestamp, OwnerID: targetIsuUUID} + if end <= 0 { + return end //要素が見つからない + } + //[0]が番兵になるかチェック + if !base[0].Less2(&target) { + return 0 //0がupperBound + } + + //線形探索 ngがbase[ng] <= targetになるまで探索 + const defaultRange = 64 + ok := end + ng := end - defaultRange + ng = (ng / defaultRange) * defaultRange //0未満になるのが嫌なので、defaultRangeの倍数にする + for base[ng].Less2(&target) { //Timestampはunique仮定なので、<で良い(等価が見つかればそれで良し) + ok = ng + ng -= defaultRange + } + + //答えは(ng, ok]内にあるはずなので、二分探索 + for ok-ng > 1 { + mid := (ok + ng) / 2 + if base[mid].Less2(&target) { + ok = mid + } else { + ng = mid + } + } + + return ok +} diff --git a/bench/scenario/verify.go b/bench/scenario/verify.go index ad8e0382c..4f8613d6e 100644 --- a/bench/scenario/verify.go +++ b/bench/scenario/verify.go @@ -11,6 +11,7 @@ import ( "net/http" "strings" + "github.com/isucon/isucon11-qualify/bench/logger" "github.com/isucon/isucon11-qualify/bench/model" "github.com/isucon/isucon11-qualify/bench/service" ) @@ -120,7 +121,8 @@ func verifyIsuConditions(res *http.Response, //expectedの開始位置を探す() baseIter := base.End(filter) - baseIter.UpperBoundIsuConditionIndex(cursor.TimestampUnix, cursor.OwnerID) + baseIter.LowerBoundIsuConditionIndex(cursor.TimestampUnix, cursor.OwnerID) + TODO_DebugMsg := fmt.Sprintf("%v -> %v -> %v (with %v)\n", base, base.End(filter), baseIter, cursor) //backendDataの先頭からチェック lastSort := model.IsuConditionCursor{TimestampUnix: backendData[0].Timestamp + 1, OwnerID: ""} @@ -141,9 +143,13 @@ func verifyIsuConditions(res *http.Response, break //ok } - if expected.TimestampUnix <= mustExistUntil { - return errorMissmatch(res, "データが足りません") + if mustExistUntil < expected.TimestampUnix { + //反映されていないことが許可されているので、無視して良い + continue } + logger.AdminLogger.Printf("%s%v vs %v", TODO_DebugMsg, expected, c) + logger.AdminLogger.Panic("データが正しくありません") + return errorMissmatch(res, "データが正しくありません") } //等価チェック From 74a3068c5a8d348297eb669d484ef0774218ef45 Mon Sep 17 00:00:00 2001 From: Nagarei Date: Fri, 9 Jul 2021 14:48:23 +0900 Subject: [PATCH 26/43] =?UTF-8?q?fix(bench):=20limit=E3=81=AE=E6=A4=9C?= =?UTF-8?q?=E8=A8=BC=E3=81=AETODO=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bench/scenario/action.go | 6 ++++++ bench/scenario/load.go | 7 ++++--- bench/scenario/verify.go | 8 +++----- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/bench/scenario/action.go b/bench/scenario/action.go index 78f874d0b..6b1bdcc52 100644 --- a/bench/scenario/action.go +++ b/bench/scenario/action.go @@ -29,6 +29,12 @@ import ( "github.com/isucon/isucon11-qualify/bench/service" ) +const ( + searchLimit = 20 + conditionLimit = 20 + isuListLimit = 200 // TODO 修正が必要なら変更 +) + //Action // ==============================initialize============================== diff --git a/bench/scenario/load.go b/bench/scenario/load.go index 164a36efc..a13500c14 100644 --- a/bench/scenario/load.go +++ b/bench/scenario/load.go @@ -182,7 +182,7 @@ scenarioLoop: getConditionFromChan(ctx, targetIsu, nil) //TODO: userConditionBuffer //conditionの検証 err := verifyIsuConditions(res, &targetIsu.Conditions, model.ConditionLevelInfo|model.ConditionLevelWarning|model.ConditionLevelCritical, - model.IsuConditionCursor{TimestampUnix: virtualNow.Unix(), OwnerID: targetIsu.JIAIsuUUID}, targetIsu.Owner.IsuListByID, + model.IsuConditionCursor{TimestampUnix: virtualNow.Unix(), OwnerID: targetIsu.JIAIsuUUID}, conditionLimit, targetIsu.Owner.IsuListByID, conditions, s.ToVirtualTime(realNow.Add(-1*time.Second)).Unix(), ) if err != nil { @@ -220,7 +220,7 @@ scenarioLoop: //検証 //ここは、古いデータのはずなのでconditionのchanからの再取得は要らない err = verifyIsuConditions(res, &targetIsu.Conditions, model.ConditionLevelInfo|model.ConditionLevelWarning|model.ConditionLevelCritical, - model.IsuConditionCursor{TimestampUnix: CursorEndTime, OwnerID: targetIsu.JIAIsuUUID}, targetIsu.Owner.IsuListByID, + model.IsuConditionCursor{TimestampUnix: CursorEndTime, OwnerID: targetIsu.JIAIsuUUID}, conditionLimit, targetIsu.Owner.IsuListByID, conditions, s.ToVirtualTime(realNow.Add(-1*time.Second)).Unix(), ) if err != nil { @@ -308,8 +308,9 @@ scenarioLoop: func(res *http.Response, conditions []*service.GetIsuConditionResponse) []error { //検証 //ここは、古いデータのはずなのでconditionのchanからの再取得は要らない + //TODO: starttimeの検証 err := verifyIsuConditions(res, &targetIsu.Conditions, model.ConditionLevelWarning|model.ConditionLevelCritical, - model.IsuConditionCursor{TimestampUnix: errorEndAtUnix, OwnerID: targetIsu.JIAIsuUUID}, targetIsu.Owner.IsuListByID, + model.IsuConditionCursor{TimestampUnix: errorEndAtUnix, OwnerID: targetIsu.JIAIsuUUID}, conditionLimit, targetIsu.Owner.IsuListByID, conditions, s.ToVirtualTime(realNow.Add(-1*time.Second)).Unix(), ) if err != nil { diff --git a/bench/scenario/verify.go b/bench/scenario/verify.go index 4f8613d6e..2f64c80b8 100644 --- a/bench/scenario/verify.go +++ b/bench/scenario/verify.go @@ -11,7 +11,6 @@ import ( "net/http" "strings" - "github.com/isucon/isucon11-qualify/bench/logger" "github.com/isucon/isucon11-qualify/bench/model" "github.com/isucon/isucon11-qualify/bench/service" ) @@ -116,13 +115,12 @@ func verifyIsuOrderByCreatedAt(res *http.Response, expectedReverse []*model.Isu, // //mustExistUntil: この値以下のtimestampを持つものは全て反映されているべき func verifyIsuConditions(res *http.Response, - base *model.IsuConditionArray, filter model.ConditionLevel, cursor model.IsuConditionCursor, isuMap map[string]*model.Isu, + base *model.IsuConditionArray, filter model.ConditionLevel, cursor model.IsuConditionCursor, limit int, isuMap map[string]*model.Isu, backendData []*service.GetIsuConditionResponse, mustExistUntil int64) error { //expectedの開始位置を探す() baseIter := base.End(filter) baseIter.LowerBoundIsuConditionIndex(cursor.TimestampUnix, cursor.OwnerID) - TODO_DebugMsg := fmt.Sprintf("%v -> %v -> %v (with %v)\n", base, base.End(filter), baseIter, cursor) //backendDataの先頭からチェック lastSort := model.IsuConditionCursor{TimestampUnix: backendData[0].Timestamp + 1, OwnerID: ""} @@ -147,8 +145,6 @@ func verifyIsuConditions(res *http.Response, //反映されていないことが許可されているので、無視して良い continue } - logger.AdminLogger.Printf("%s%v vs %v", TODO_DebugMsg, expected, c) - logger.AdminLogger.Panic("データが正しくありません") return errorMissmatch(res, "データが正しくありません") } @@ -189,5 +185,7 @@ func verifyIsuConditions(res *http.Response, lastSort = nowSort } + //TODO: limitの検証 + return nil } From 4ce0fd42786a20b80eb0a022a666e5d638f76e50 Mon Sep 17 00:00:00 2001 From: Nagarei Date: Fri, 9 Jul 2021 15:10:19 +0900 Subject: [PATCH 27/43] =?UTF-8?q?fix(bench):=20=E6=A4=9C=E8=A8=BC=E5=AF=BE?= =?UTF-8?q?=E8=B1=A1=E3=81=8C=E9=96=93=E9=81=95=E3=81=A3=E3=81=A6=E3=81=84?= =?UTF-8?q?=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bench/scenario/load.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/scenario/load.go b/bench/scenario/load.go index a13500c14..ae2a66f2b 100644 --- a/bench/scenario/load.go +++ b/bench/scenario/load.go @@ -221,7 +221,7 @@ scenarioLoop: //ここは、古いデータのはずなのでconditionのchanからの再取得は要らない err = verifyIsuConditions(res, &targetIsu.Conditions, model.ConditionLevelInfo|model.ConditionLevelWarning|model.ConditionLevelCritical, model.IsuConditionCursor{TimestampUnix: CursorEndTime, OwnerID: targetIsu.JIAIsuUUID}, conditionLimit, targetIsu.Owner.IsuListByID, - conditions, s.ToVirtualTime(realNow.Add(-1*time.Second)).Unix(), + conditionsTmp, s.ToVirtualTime(realNow.Add(-1*time.Second)).Unix(), ) if err != nil { scenarioSuccess = false From 6efad6da87a8c102334c6833f7976407004747e7 Mon Sep 17 00:00:00 2001 From: Nagarei Date: Fri, 9 Jul 2021 15:11:01 +0900 Subject: [PATCH 28/43] =?UTF-8?q?fix(bench):=20backendData=E3=81=8C0?= =?UTF-8?q?=E3=81=AE=E3=81=A8=E3=81=8D=E3=81=AE=E3=82=A8=E3=83=A9=E3=83=BC?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bench/scenario/verify.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bench/scenario/verify.go b/bench/scenario/verify.go index 2f64c80b8..ebe68941a 100644 --- a/bench/scenario/verify.go +++ b/bench/scenario/verify.go @@ -120,13 +120,13 @@ func verifyIsuConditions(res *http.Response, //expectedの開始位置を探す() baseIter := base.End(filter) - baseIter.LowerBoundIsuConditionIndex(cursor.TimestampUnix, cursor.OwnerID) + baseIter.UpperBoundIsuConditionIndex(cursor.TimestampUnix, cursor.OwnerID) //TODO: Lowerなきがする //backendDataの先頭からチェック - lastSort := model.IsuConditionCursor{TimestampUnix: backendData[0].Timestamp + 1, OwnerID: ""} - for _, c := range backendData { + var lastSort model.IsuConditionCursor + for i, c := range backendData { nowSort := model.IsuConditionCursor{TimestampUnix: c.Timestamp, OwnerID: c.JIAIsuUUID} - if !nowSort.Less(&lastSort) { + if i != 0 && !nowSort.Less(&lastSort) { return errorInvalid(res, "整列順が正しくありません") } From 29508d672a7b00a5e155c1e06c6d1e33ef7a6515 Mon Sep 17 00:00:00 2001 From: Nagarei Date: Fri, 9 Jul 2021 15:14:40 +0900 Subject: [PATCH 29/43] fix(bench): fix bug --- bench/model/isuCondition.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bench/model/isuCondition.go b/bench/model/isuCondition.go index 09f243f9f..2070955de 100644 --- a/bench/model/isuCondition.go +++ b/bench/model/isuCondition.go @@ -211,7 +211,7 @@ func lowerBoundIsuConditionIndex(base []IsuCondition, end int, targetTimestamp i ok := end ng := end - defaultRange ng = (ng / defaultRange) * defaultRange //0未満になるのが嫌なので、defaultRangeの倍数にする - for base[ng].Less2(&target) { //Timestampはunique仮定なので、<で良い(等価が見つかればそれで良し) + for !base[ng].Less2(&target) { //Timestampはunique仮定なので、<で良い(等価が見つかればそれで良し) ok = ng ng -= defaultRange } @@ -219,7 +219,7 @@ func lowerBoundIsuConditionIndex(base []IsuCondition, end int, targetTimestamp i //答えは(ng, ok]内にあるはずなので、二分探索 for ok-ng > 1 { mid := (ok + ng) / 2 - if base[mid].Less2(&target) { + if !base[mid].Less2(&target) { ok = mid } else { ng = mid From fe137174fcb7a1fb40b42e0baff7f30cc200c258 Mon Sep 17 00:00:00 2001 From: Nagarei Date: Fri, 9 Jul 2021 15:35:15 +0900 Subject: [PATCH 30/43] =?UTF-8?q?fix(backend):=20=E5=A2=83=E7=95=8C?= =?UTF-8?q?=E6=9D=A1=E4=BB=B6=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bench/scenario/verify.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/scenario/verify.go b/bench/scenario/verify.go index ebe68941a..04d91e733 100644 --- a/bench/scenario/verify.go +++ b/bench/scenario/verify.go @@ -120,7 +120,7 @@ func verifyIsuConditions(res *http.Response, //expectedの開始位置を探す() baseIter := base.End(filter) - baseIter.UpperBoundIsuConditionIndex(cursor.TimestampUnix, cursor.OwnerID) //TODO: Lowerなきがする + baseIter.LowerBoundIsuConditionIndex(cursor.TimestampUnix, cursor.OwnerID) //backendDataの先頭からチェック var lastSort model.IsuConditionCursor From b883420bed31a00eab3bcac90169fbc79e52d335 Mon Sep 17 00:00:00 2001 From: Nagarei Date: Fri, 9 Jul 2021 15:43:42 +0900 Subject: [PATCH 31/43] =?UTF-8?q?feat(bench):=20limit=E3=81=AE=E6=A4=9C?= =?UTF-8?q?=E8=A8=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bench/scenario/verify.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/bench/scenario/verify.go b/bench/scenario/verify.go index 04d91e733..6f8b86c39 100644 --- a/bench/scenario/verify.go +++ b/bench/scenario/verify.go @@ -118,6 +118,10 @@ func verifyIsuConditions(res *http.Response, base *model.IsuConditionArray, filter model.ConditionLevel, cursor model.IsuConditionCursor, limit int, isuMap map[string]*model.Isu, backendData []*service.GetIsuConditionResponse, mustExistUntil int64) error { + if limit < len(backendData) { + return errorInvalid(res, "要素数が正しくありません") + } + //expectedの開始位置を探す() baseIter := base.End(filter) baseIter.LowerBoundIsuConditionIndex(cursor.TimestampUnix, cursor.OwnerID) @@ -185,7 +189,10 @@ func verifyIsuConditions(res *http.Response, lastSort = nowSort } - //TODO: limitの検証 + //limitの検証 + if len(backendData) < limit && baseIter.Prev() != nil { + return errorInvalid(res, "要素数が正しくありません") + } return nil } From 9a0efc1882252d4eb7607f0efe7ab8ce2aea388b Mon Sep 17 00:00:00 2001 From: Nagarei Date: Fri, 9 Jul 2021 16:19:44 +0900 Subject: [PATCH 32/43] =?UTF-8?q?fix(bench):=20verifyIsuConditions?= =?UTF-8?q?=E3=81=AE=E5=BC=95=E6=95=B0=E6=95=B4=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bench/model/user.go | 2 +- bench/scenario/load.go | 58 +++++++++++++++++++--------------------- bench/scenario/verify.go | 29 ++++++++++++++++---- 3 files changed, 52 insertions(+), 37 deletions(-) diff --git a/bench/model/user.go b/bench/model/user.go index 9c9f2fd89..b606b8520 100644 --- a/bench/model/user.go +++ b/bench/model/user.go @@ -23,7 +23,7 @@ type User struct { Type UserType IsuListOrderByCreatedAt []*Isu //CreatedAtは厳密にはわからないので、postした後にgetをした順番を正とする IsuListByID map[string]*Isu //IDをkeyにアクセス - //ここで[]IsuLogを持つと更新にmutexが必要で嫌なので持たない + Conditions IsuConditionArray Agent *agent.Agent } diff --git a/bench/scenario/load.go b/bench/scenario/load.go index ae2a66f2b..fe3e04c1a 100644 --- a/bench/scenario/load.go +++ b/bench/scenario/load.go @@ -169,20 +169,18 @@ scenarioLoop: //定期的にconditionを見に行くシナリオ realNow = time.Now() virtualNow = s.ToVirtualTime(realNow) + request := service.GetIsuConditionRequest{ + StartTime: nil, + CursorEndTime: uint64(virtualNow.Unix()), + CursorJIAIsuUUID: "", + ConditionLevel: "info,warning,critical", + Limit: nil, + } _, conditions, errs := browserGetIsuConditionAction(ctx, user.Agent, targetIsu.JIAIsuUUID, - service.GetIsuConditionRequest{ - StartTime: nil, - CursorEndTime: uint64(virtualNow.Unix()), - CursorJIAIsuUUID: "", - ConditionLevel: "info,warning,critical", - Limit: nil, - }, + request, func(res *http.Response, conditions []*service.GetIsuConditionResponse) []error { - //検証前にデータ取得 - getConditionFromChan(ctx, targetIsu, nil) //TODO: userConditionBuffer //conditionの検証 - err := verifyIsuConditions(res, &targetIsu.Conditions, model.ConditionLevelInfo|model.ConditionLevelWarning|model.ConditionLevelCritical, - model.IsuConditionCursor{TimestampUnix: virtualNow.Unix(), OwnerID: targetIsu.JIAIsuUUID}, conditionLimit, targetIsu.Owner.IsuListByID, + err := verifyIsuConditions(res, user, targetIsu.JIAIsuUUID, &request, conditions, s.ToVirtualTime(realNow.Add(-1*time.Second)).Unix(), ) if err != nil { @@ -203,15 +201,14 @@ scenarioLoop: for i := 0; i < 2 && len(conditions) == 20*(i+1); i++ { var conditionsTmp []*service.GetIsuConditionResponse CursorEndTime := conditions[len(conditions)-1].Timestamp - conditionsTmp, res, err := getIsuConditionAction(ctx, user.Agent, targetIsu.JIAIsuUUID, - service.GetIsuConditionRequest{ - StartTime: nil, - CursorEndTime: uint64(CursorEndTime), - CursorJIAIsuUUID: "", - ConditionLevel: "info,warning,critical", - Limit: nil, - }, - ) + request = service.GetIsuConditionRequest{ + StartTime: nil, + CursorEndTime: uint64(CursorEndTime), + CursorJIAIsuUUID: "", + ConditionLevel: "info,warning,critical", + Limit: nil, + } + conditionsTmp, res, err := getIsuConditionAction(ctx, user.Agent, targetIsu.JIAIsuUUID, request) if err != nil { scenarioSuccess = false step.AddError(err) @@ -219,8 +216,7 @@ scenarioLoop: } //検証 //ここは、古いデータのはずなのでconditionのchanからの再取得は要らない - err = verifyIsuConditions(res, &targetIsu.Conditions, model.ConditionLevelInfo|model.ConditionLevelWarning|model.ConditionLevelCritical, - model.IsuConditionCursor{TimestampUnix: CursorEndTime, OwnerID: targetIsu.JIAIsuUUID}, conditionLimit, targetIsu.Owner.IsuListByID, + err = verifyIsuConditions(res, user, targetIsu.JIAIsuUUID, &request, conditionsTmp, s.ToVirtualTime(realNow.Add(-1*time.Second)).Unix(), ) if err != nil { @@ -297,20 +293,20 @@ scenarioLoop: //悪いものがあれば、そのconditionを取る if errorEndAtUnix != 0 { startTime := uint64(errorEndAtUnix - 60*60) + request := service.GetIsuConditionRequest{ + StartTime: &startTime, + CursorEndTime: uint64(errorEndAtUnix), + CursorJIAIsuUUID: "", + ConditionLevel: "warning,critical", + Limit: nil, + } _, conditions, errs := browserGetIsuConditionAction(ctx, user.Agent, targetIsu.JIAIsuUUID, - service.GetIsuConditionRequest{ - StartTime: &startTime, - CursorEndTime: uint64(errorEndAtUnix), - CursorJIAIsuUUID: "", - ConditionLevel: "warning,critical", - Limit: nil, - }, + request, func(res *http.Response, conditions []*service.GetIsuConditionResponse) []error { //検証 //ここは、古いデータのはずなのでconditionのchanからの再取得は要らない //TODO: starttimeの検証 - err := verifyIsuConditions(res, &targetIsu.Conditions, model.ConditionLevelWarning|model.ConditionLevelCritical, - model.IsuConditionCursor{TimestampUnix: errorEndAtUnix, OwnerID: targetIsu.JIAIsuUUID}, conditionLimit, targetIsu.Owner.IsuListByID, + err := verifyIsuConditions(res, user, targetIsu.JIAIsuUUID, &request, conditions, s.ToVirtualTime(realNow.Add(-1*time.Second)).Unix(), ) if err != nil { diff --git a/bench/scenario/verify.go b/bench/scenario/verify.go index 6f8b86c39..2ead0a0f3 100644 --- a/bench/scenario/verify.go +++ b/bench/scenario/verify.go @@ -115,16 +115,35 @@ func verifyIsuOrderByCreatedAt(res *http.Response, expectedReverse []*model.Isu, // //mustExistUntil: この値以下のtimestampを持つものは全て反映されているべき func verifyIsuConditions(res *http.Response, - base *model.IsuConditionArray, filter model.ConditionLevel, cursor model.IsuConditionCursor, limit int, isuMap map[string]*model.Isu, + targetUser *model.User, targetIsuUUID string, request *service.GetIsuConditionRequest, backendData []*service.GetIsuConditionResponse, mustExistUntil int64) error { + var limit int + if request.Limit != nil { + limit = int(*request.Limit) + } else { + limit = conditionLimit + } if limit < len(backendData) { return errorInvalid(res, "要素数が正しくありません") } - //expectedの開始位置を探す() - baseIter := base.End(filter) - baseIter.LowerBoundIsuConditionIndex(cursor.TimestampUnix, cursor.OwnerID) + //expectedの開始位置を探す + filter := model.ConditionLevelNone + for _, level := range strings.Split(request.ConditionLevel, ",") { + switch level[0] { + case 'i': + filter |= model.ConditionLevelInfo + case 'w': + filter |= model.ConditionLevelWarning + case 'c': + filter |= model.ConditionLevelCritical + } + } + targetIsu := targetUser.IsuListByID[targetIsuUUID] + targetConditions := &targetIsu.Conditions + baseIter := targetConditions.End(filter) + baseIter.LowerBoundIsuConditionIndex(int64(request.CursorEndTime), request.CursorJIAIsuUUID) //backendDataの先頭からチェック var lastSort model.IsuConditionCursor @@ -182,7 +201,7 @@ func verifyIsuConditions(res *http.Response, c.IsSitting != expected.IsSitting || c.JIAIsuUUID != expected.OwnerID || c.Message != expected.Message || - c.IsuName != isuMap[expected.OwnerID].Name { + c.IsuName != targetIsu.Name { return errorMissmatch(res, "データが正しくありません") } From 81b883c6b5feb357e761237d911e3d53a0a964a8 Mon Sep 17 00:00:00 2001 From: Nagarei Date: Fri, 9 Jul 2021 16:35:13 +0900 Subject: [PATCH 33/43] fix(bench): user.GetConditionFromChan --- bench/model/isu.go | 28 +++++++++++++++++++++++++++- bench/model/user.go | 7 +++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/bench/model/isu.go b/bench/model/isu.go index 9bfdaa367..697acd386 100644 --- a/bench/model/isu.go +++ b/bench/model/isu.go @@ -1,6 +1,9 @@ package model -import "fmt" +import ( + "context" + "fmt" +) //enum type IsuStateChange int @@ -94,3 +97,26 @@ func (isu *Isu) IsDeactivated() bool { } return isu.isDeactivated } + +func (isu *Isu) getConditionFromChan(ctx context.Context, userConditionBuffer *IsuConditionArray) { + for { + select { + case <-ctx.Done(): + return + case conditions, ok := <-isu.StreamsForScenario.ConditionChan: + if !ok { + return + } + for _, c := range conditions { + isu.Conditions.Add(&c) + } + if userConditionBuffer != nil { + for _, c := range conditions { + userConditionBuffer.Add(&c) + } + } + default: + return + } + } +} diff --git a/bench/model/user.go b/bench/model/user.go index b606b8520..8a2cb0960 100644 --- a/bench/model/user.go +++ b/bench/model/user.go @@ -1,6 +1,7 @@ package model import ( + "context" "math/rand" "github.com/isucon/isucandar/agent" @@ -48,6 +49,12 @@ func (u *User) AddIsu(isu *Isu) { u.IsuListByID[isu.JIAIsuUUID] = isu } +func (user *User) GetConditionFromChan(ctx context.Context) { + for _, isu := range user.IsuListOrderByCreatedAt { + isu.getConditionFromChan(ctx, &user.Conditions) + } +} + // utility //TODO: 差し替える From bc723da5227a3472772f1e844c3901a0231d6a63 Mon Sep 17 00:00:00 2001 From: Nagarei Date: Fri, 9 Jul 2021 17:03:56 +0900 Subject: [PATCH 34/43] fix(bench): user.GetConditionFromChan --- bench/scenario/load.go | 33 +++------------------------------ 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/bench/scenario/load.go b/bench/scenario/load.go index fe3e04c1a..909b75a92 100644 --- a/bench/scenario/load.go +++ b/bench/scenario/load.go @@ -116,9 +116,7 @@ scenarioLoop: scenarioSuccess = true //posterからconditionの取得 - for _, isu := range user.IsuListOrderByCreatedAt { - getConditionFromChan(ctx, isu, nil) //TODO: userConditionBuffer - } + user.GetConditionFromChan(ctx) select { case <-ctx.Done(): return @@ -138,8 +136,6 @@ scenarioLoop: return verifyIsuOrderByCreatedAt(res, user.IsuListOrderByCreatedAt, isuList) }, func(res *http.Response, conditions []*service.GetIsuConditionResponse) []error { - //検証前にデータ取得 - getConditionFromChan(ctx, targetIsu, nil) //TODO: userConditionBuffer //TODO: conditionの検証 return []error{} }, @@ -256,8 +252,8 @@ scenarioLoop: _, graphToday, errs := browserGetIsuGraphAction(ctx, user.Agent, targetIsu.JIAIsuUUID, uint64(virtualToday.Unix()), func(res *http.Response, graph []*service.GraphResponse) []error { //検証前にデータ取得 - getConditionFromChan(ctx, targetIsu, nil) //TODO: userConditionBuffer - return []error{} //TODO: 検証 + user.GetConditionFromChan(ctx) + return []error{} //TODO: 検証 }, ) for _, err := range errs { @@ -334,29 +330,6 @@ scenarioLoop: } } -func getConditionFromChan(ctx context.Context, isu *model.Isu, userConditionBuffer *model.IsuConditionArray) { - for { - select { - case <-ctx.Done(): - return - case conditions, ok := <-isu.StreamsForScenario.ConditionChan: - if !ok { - return - } - for _, c := range conditions { - isu.Conditions.Add(&c) - } - if userConditionBuffer != nil { - for _, c := range conditions { - userConditionBuffer.Add(&c) - } - } - default: - return - } - } -} - func findBadIsuState(conditions []*service.GetIsuConditionResponse) (model.IsuStateChange, int64) { //TODO: すでに改善済みのものを弾く From 4b840833d32831551d00934628575014cee6df91 Mon Sep 17 00:00:00 2001 From: Nagarei Date: Fri, 9 Jul 2021 17:22:34 +0900 Subject: [PATCH 35/43] =?UTF-8?q?fix(bench):=20=E6=A4=9C=E8=A8=BC=E5=8F=AF?= =?UTF-8?q?=E8=83=BD=E3=81=AA=E7=AF=84=E5=9B=B2=E3=81=A7=E3=83=AA=E3=82=AF?= =?UTF-8?q?=E3=82=A8=E3=82=B9=E3=83=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bench/model/isuCondition.go | 5 +++++ bench/scenario/load.go | 24 ++++++++++-------------- bench/scenario/scenario.go | 18 ++++++++++++++++++ 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/bench/model/isuCondition.go b/bench/model/isuCondition.go index 2070955de..dcd77d27d 100644 --- a/bench/model/isuCondition.go +++ b/bench/model/isuCondition.go @@ -99,6 +99,11 @@ func (ia *IsuConditionArray) End(filter ConditionLevel) IsuConditionIterator { } } +func (ia *IsuConditionArray) Back() *IsuCondition { + iter := ia.End(ConditionLevelInfo | ConditionLevelWarning | ConditionLevelCritical) + return iter.Prev() +} + func (iter *IsuConditionIterator) UpperBoundIsuConditionIndex(targetTimestamp int64, targetIsuUUID string) { if (iter.filter & ConditionLevelInfo) != 0 { iter.indexInfo = upperBoundIsuConditionIndex(iter.parent.Info, len(iter.parent.Info), targetTimestamp, targetIsuUUID) diff --git a/bench/scenario/load.go b/bench/scenario/load.go index 909b75a92..2c14e6d1d 100644 --- a/bench/scenario/load.go +++ b/bench/scenario/load.go @@ -127,11 +127,11 @@ scenarioLoop: nextTargetIsuIndex += 1 nextTargetIsuIndex %= isuCount targetIsu := user.IsuListOrderByCreatedAt[nextTargetIsuIndex] + mustExistUntil := s.ToVirtualTime(time.Now().Add(-1 * time.Second)).Unix() //GET / - realNow := time.Now() - virtualNow := s.ToVirtualTime(realNow) - _, _, errs := browserGetHomeAction(ctx, user.Agent, virtualNow.Unix(), + dataExistTimestamp := GetConditionDataExistTimestamp(s, user) + _, _, errs := browserGetHomeAction(ctx, user.Agent, dataExistTimestamp, func(res *http.Response, isuList []*service.Isu) []error { return verifyIsuOrderByCreatedAt(res, user.IsuListOrderByCreatedAt, isuList) }, @@ -163,11 +163,9 @@ scenarioLoop: //TODO: リロード //定期的にconditionを見に行くシナリオ - realNow = time.Now() - virtualNow = s.ToVirtualTime(realNow) request := service.GetIsuConditionRequest{ StartTime: nil, - CursorEndTime: uint64(virtualNow.Unix()), + CursorEndTime: uint64(dataExistTimestamp), CursorJIAIsuUUID: "", ConditionLevel: "info,warning,critical", Limit: nil, @@ -177,7 +175,7 @@ scenarioLoop: func(res *http.Response, conditions []*service.GetIsuConditionResponse) []error { //conditionの検証 err := verifyIsuConditions(res, user, targetIsu.JIAIsuUUID, &request, - conditions, s.ToVirtualTime(realNow.Add(-1*time.Second)).Unix(), + conditions, mustExistUntil, ) if err != nil { return []error{err} @@ -213,7 +211,7 @@ scenarioLoop: //検証 //ここは、古いデータのはずなのでconditionのchanからの再取得は要らない err = verifyIsuConditions(res, user, targetIsu.JIAIsuUUID, &request, - conditionsTmp, s.ToVirtualTime(realNow.Add(-1*time.Second)).Unix(), + conditionsTmp, mustExistUntil, ) if err != nil { scenarioSuccess = false @@ -246,10 +244,8 @@ scenarioLoop: } else { //TODO: graphを見に行くシナリオ - realNow = time.Now() - virtualNow = s.ToVirtualTime(realNow) - virtualToday := time.Date(virtualNow.Year(), virtualNow.Month(), virtualNow.Day(), 0, 0, 0, 0, virtualNow.Location()) - _, graphToday, errs := browserGetIsuGraphAction(ctx, user.Agent, targetIsu.JIAIsuUUID, uint64(virtualToday.Unix()), + virtualToday := (dataExistTimestamp / (24 * 60 * 60)) * (24 * 60 * 60) + _, graphToday, errs := browserGetIsuGraphAction(ctx, user.Agent, targetIsu.JIAIsuUUID, uint64(virtualToday), func(res *http.Response, graph []*service.GraphResponse) []error { //検証前にデータ取得 user.GetConditionFromChan(ctx) @@ -265,7 +261,7 @@ scenarioLoop: } //前日のグラフ - _, _, errs = browserGetIsuGraphAction(ctx, user.Agent, targetIsu.JIAIsuUUID, uint64(virtualToday.Add(-24*time.Hour).Unix()), + _, _, errs = browserGetIsuGraphAction(ctx, user.Agent, targetIsu.JIAIsuUUID, uint64(virtualToday-60*60), func(res *http.Response, graph []*service.GraphResponse) []error { return []error{} //TODO: 検証 }, @@ -303,7 +299,7 @@ scenarioLoop: //ここは、古いデータのはずなのでconditionのchanからの再取得は要らない //TODO: starttimeの検証 err := verifyIsuConditions(res, user, targetIsu.JIAIsuUUID, &request, - conditions, s.ToVirtualTime(realNow.Add(-1*time.Second)).Unix(), + conditions, mustExistUntil, ) if err != nil { return []error{err} diff --git a/bench/scenario/scenario.go b/bench/scenario/scenario.go index 130e712ea..93df72831 100644 --- a/bench/scenario/scenario.go +++ b/bench/scenario/scenario.go @@ -2,6 +2,7 @@ package scenario import ( "context" + "math" "sync" "time" @@ -157,3 +158,20 @@ func (s *Scenario) NewIsu(ctx context.Context, step *isucandar.BenchmarkStep, ow return isu } + +func GetConditionDataExistTimestamp(s *Scenario, user *model.User) int64 { + if len(user.IsuListOrderByCreatedAt) == 0 { + return s.virtualTimeStart.Unix() + } + var timestamp int64 = math.MaxInt64 + for _, isu := range user.IsuListOrderByCreatedAt { + cond := isu.Conditions.Back() + if cond == nil { + return s.virtualTimeStart.Unix() + } + if cond.TimestampUnix < timestamp { + timestamp = cond.TimestampUnix + } + } + return timestamp +} From 3115dd2a2405a4e5601ba6219422fb69b0201a63 Mon Sep 17 00:00:00 2001 From: ryoha000 Date: Fri, 9 Jul 2021 17:57:33 +0900 Subject: [PATCH 36/43] fix(frontend) fix new date unix time --- webapp/frontend/src/components/Condition/ConditionDetail.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/frontend/src/components/Condition/ConditionDetail.tsx b/webapp/frontend/src/components/Condition/ConditionDetail.tsx index 91f27790b..fd962a982 100644 --- a/webapp/frontend/src/components/Condition/ConditionDetail.tsx +++ b/webapp/frontend/src/components/Condition/ConditionDetail.tsx @@ -6,7 +6,7 @@ interface Props { } const getTime = (condition: Condition) => { - const date = new Date(condition.timestamp) + const date = new Date(condition.timestamp * 1000) // 2020/01/01 01:01:01 return `${date.getUTCFullYear()}/${pad0(date.getUTCMonth() + 1)}/${pad0( date.getUTCDate() From 29b8ec7bc7729037713b24bf3e7e86bf11db3224 Mon Sep 17 00:00:00 2001 From: Nagarei Date: Fri, 9 Jul 2021 18:52:18 +0900 Subject: [PATCH 37/43] =?UTF-8?q?fix(bench):=20StartTime=E3=82=92=E8=80=83?= =?UTF-8?q?=E6=85=AE=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bench/scenario/verify.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/bench/scenario/verify.go b/bench/scenario/verify.go index 2ead0a0f3..985a07867 100644 --- a/bench/scenario/verify.go +++ b/bench/scenario/verify.go @@ -118,6 +118,7 @@ func verifyIsuConditions(res *http.Response, targetUser *model.User, targetIsuUUID string, request *service.GetIsuConditionRequest, backendData []*service.GetIsuConditionResponse, mustExistUntil int64) error { + //limitを超えているかチェック var limit int if request.Limit != nil { limit = int(*request.Limit) @@ -127,6 +128,10 @@ func verifyIsuConditions(res *http.Response, if limit < len(backendData) { return errorInvalid(res, "要素数が正しくありません") } + //レスポンス側のstartTimeのチェック + if request.StartTime != nil && len(backendData) != 0 && backendData[len(backendData)-1].Timestamp < int64(*request.StartTime) { + return errorInvalid(res, "データが正しくありません") + } //expectedの開始位置を探す filter := model.ConditionLevelNone @@ -210,7 +215,10 @@ func verifyIsuConditions(res *http.Response, //limitの検証 if len(backendData) < limit && baseIter.Prev() != nil { - return errorInvalid(res, "要素数が正しくありません") + prev := baseIter.Prev() + if prev != nil && request.StartTime != nil && int64(*request.StartTime) <= prev.TimestampUnix { + return errorInvalid(res, "要素数が正しくありません") + } } return nil From cbed4a307a3878aea77f710eca876e65390f56c5 Mon Sep 17 00:00:00 2001 From: mofumofuchan Date: Fri, 9 Jul 2021 19:07:21 +0900 Subject: [PATCH 38/43] =?UTF-8?q?fix(bench)=20ISU=E3=81=8B=E3=82=89IsuCond?= =?UTF-8?q?ition=E3=81=ABpost=E3=81=99=E3=82=8B=E3=83=87=E3=83=BC=E3=82=BF?= =?UTF-8?q?=E3=82=92=E9=85=8D=E5=88=97=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extra/jiaapi/cmd/standalone/main.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/extra/jiaapi/cmd/standalone/main.go b/extra/jiaapi/cmd/standalone/main.go index 977650c3f..0d38ad027 100644 --- a/extra/jiaapi/cmd/standalone/main.go +++ b/extra/jiaapi/cmd/standalone/main.go @@ -331,7 +331,7 @@ func (state *IsuConditionPoster) keepPosting(ctx context.Context) { nowTime := time.Now() randEngine.Seed(nowTime.UnixNano()/1000000000 + 961054102) - notification, err := json.Marshal(IsuNotification{ + notification := IsuNotification{ IsSitting: (randEngine.Intn(100) <= 70), Condition: fmt.Sprintf("is_dirty=%v,is_overweight=%v,is_broken=%v", (randEngine.Intn(2) == 0), @@ -340,16 +340,20 @@ func (state *IsuConditionPoster) keepPosting(ctx context.Context) { ), Message: "今日もいい天気", Timestamp: nowTime.Unix(), - }) + } + notifications := []IsuNotification{notification} + payload, err := json.Marshal(notifications) if err != nil { log.Error(err) continue } func() { + fmt.Println("go go go!!") + resp, err := http.Post( targetURL, "application/json", - bytes.NewBuffer(notification), + bytes.NewBuffer(payload), ) if err != nil { log.Error(err) From 00e01322a60e8787e2fea4b350c44450aa057e45 Mon Sep 17 00:00:00 2001 From: ryoha000 Date: Fri, 9 Jul 2021 19:10:54 +0900 Subject: [PATCH 39/43] =?UTF-8?q?feat(frontend)=20Icon=E3=81=AE=E3=83=9C?= =?UTF-8?q?=E3=82=BF=E3=83=B3=E3=82=92=E4=B8=AD=E5=A4=AE=E6=8F=83=E3=81=88?= =?UTF-8?q?=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/IsuDetail/NameEdit.tsx | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/webapp/frontend/src/components/IsuDetail/NameEdit.tsx b/webapp/frontend/src/components/IsuDetail/NameEdit.tsx index ac69f6e53..edd144f81 100644 --- a/webapp/frontend/src/components/IsuDetail/NameEdit.tsx +++ b/webapp/frontend/src/components/IsuDetail/NameEdit.tsx @@ -48,10 +48,16 @@ const FinishEditButtons = ({ }) => { return (
- -
@@ -60,7 +66,10 @@ const FinishEditButtons = ({ const StartEditButton = ({ startEdit }: { startEdit: () => void }) => { return ( - ) From 989a70db7578ae853b0301cd66d0300d0a73b3f1 Mon Sep 17 00:00:00 2001 From: mofumofuchan Date: Fri, 9 Jul 2021 19:10:56 +0900 Subject: [PATCH 40/43] =?UTF-8?q?fix(bench)=20=E6=AE=8B=E3=81=A3=E3=81=A6?= =?UTF-8?q?=E3=81=84=E3=81=9F=E3=83=87=E3=83=90=E3=83=83=E3=82=B0=E7=94=A8?= =?UTF-8?q?=E3=82=B3=E3=83=BC=E3=83=89=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extra/jiaapi/cmd/standalone/main.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/extra/jiaapi/cmd/standalone/main.go b/extra/jiaapi/cmd/standalone/main.go index 0d38ad027..cf461eaef 100644 --- a/extra/jiaapi/cmd/standalone/main.go +++ b/extra/jiaapi/cmd/standalone/main.go @@ -349,8 +349,6 @@ func (state *IsuConditionPoster) keepPosting(ctx context.Context) { } func() { - fmt.Println("go go go!!") - resp, err := http.Post( targetURL, "application/json", bytes.NewBuffer(payload), From 7742cc6d4684a2d432ba1a14304a6a310dccf52a Mon Sep 17 00:00:00 2001 From: ryoha000 Date: Fri, 9 Jul 2021 19:17:30 +0900 Subject: [PATCH 41/43] =?UTF-8?q?fix(frontend)=20logout=E3=81=AE=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../frontend/src/components/PageHeader/UserControlModal.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/webapp/frontend/src/components/PageHeader/UserControlModal.tsx b/webapp/frontend/src/components/PageHeader/UserControlModal.tsx index 9e8fff77b..e64aa8105 100644 --- a/webapp/frontend/src/components/PageHeader/UserControlModal.tsx +++ b/webapp/frontend/src/components/PageHeader/UserControlModal.tsx @@ -2,6 +2,7 @@ import Modal from 'react-modal' import { IoMdLogOut } from 'react-icons/io' import { Link } from 'react-router-dom' import { useDispatchContext } from '../../context/state' +import apis from '../../lib/apis' interface Props { isOpen: boolean @@ -10,7 +11,8 @@ interface Props { const UserControlModal = (props: Props) => { const dispatch = useDispatchContext() - const logout = () => { + const logout = async () => { + await apis.postSignout() dispatch({ type: 'logout' }) } From 2765085605bae43357ba805907cd1d314f875b69 Mon Sep 17 00:00:00 2001 From: "oribe(oribe1115)" Date: Fri, 9 Jul 2021 19:30:40 +0900 Subject: [PATCH 42/43] =?UTF-8?q?fix(frontend):=20=E4=BD=BF=E3=81=A3?= =?UTF-8?q?=E3=81=A6=E3=81=84=E3=81=AA=E3=81=84=E9=96=A2=E6=95=B0=E3=82=92?= =?UTF-8?q?=E6=B6=88=E5=8E=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- webapp/frontend/src/components/IsuGraph/DateInput.tsx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/webapp/frontend/src/components/IsuGraph/DateInput.tsx b/webapp/frontend/src/components/IsuGraph/DateInput.tsx index 4cfddf79d..af7093b5c 100644 --- a/webapp/frontend/src/components/IsuGraph/DateInput.tsx +++ b/webapp/frontend/src/components/IsuGraph/DateInput.tsx @@ -28,11 +28,4 @@ const DateInput = ({ day, fetchGraphs }: Props) => { ) } -const dateToStr = (date: Date) => { - return `${date.getUTCFullYear()}/${pad0(date.getUTCMonth() + 1)}/${pad0( - date.getUTCDate() - )} ` -} -const pad0 = (num: number) => ('0' + num).slice(-2) - export default DateInput From 884d4762348b4ab861d267463ab76dc28642b603 Mon Sep 17 00:00:00 2001 From: Nagarei Date: Fri, 9 Jul 2021 19:36:36 +0900 Subject: [PATCH 43/43] fix(bench): lastSolvedTime --- bench/scenario/load.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/bench/scenario/load.go b/bench/scenario/load.go index 2c14e6d1d..c3fad68d0 100644 --- a/bench/scenario/load.go +++ b/bench/scenario/load.go @@ -89,7 +89,10 @@ func (s *Scenario) loadNormalUser(ctx context.Context, step *isucandar.Benchmark nextTargetIsuIndex := 0 scenarioDoneCount := 0 scenarioSuccess := false - lastSolvedTime := s.virtualTimeStart + lastSolvedTime := make(map[string]time.Time) + for _, isu := range user.IsuListOrderByCreatedAt { + lastSolvedTime[isu.JIAIsuUUID] = s.virtualTimeStart + } scenarioLoop: for { select { @@ -224,7 +227,7 @@ scenarioLoop: //conditionを確認して、椅子状態を改善 solvedCondition, findTimestamp := findBadIsuState(conditions) - if solvedCondition != model.IsuStateChangeNone && lastSolvedTime.Before(time.Unix(findTimestamp, 0)) { + if solvedCondition != model.IsuStateChangeNone && lastSolvedTime[targetIsu.JIAIsuUUID].Before(time.Unix(findTimestamp, 0)) { //graphを見る virtualDay := (findTimestamp / (24 * 60 * 60)) * (24 * 60 * 60) _, _, errs := browserGetIsuGraphAction(ctx, user.Agent, targetIsu.JIAIsuUUID, uint64(virtualDay), @@ -238,7 +241,7 @@ scenarioLoop: } //状態改善 - lastSolvedTime = time.Unix(findTimestamp, 0) + lastSolvedTime[targetIsu.JIAIsuUUID] = time.Unix(findTimestamp, 0) targetIsu.StreamsForScenario.StateChan <- solvedCondition //バッファがあるのでブロック率は低い読みで直列に投げる } } else { @@ -317,8 +320,8 @@ scenarioLoop: //状態改善 solvedCondition, findTimestamp := findBadIsuState(conditions) - if solvedCondition != model.IsuStateChangeNone && lastSolvedTime.Before(time.Unix(findTimestamp, 0)) { - lastSolvedTime = time.Unix(findTimestamp, 0) + if solvedCondition != model.IsuStateChangeNone && lastSolvedTime[targetIsu.JIAIsuUUID].Before(time.Unix(findTimestamp, 0)) { + lastSolvedTime[targetIsu.JIAIsuUUID] = time.Unix(findTimestamp, 0) targetIsu.StreamsForScenario.StateChan <- solvedCondition //バッファがあるのでブロック率は低い読みで直列に投げる } }