Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rank design and implement, in progress. #99

Merged
merged 8 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions cmd/clean/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import (
"context"

"github.com/minio/minio-go/v7"
casbin_agent "github.com/oj-lab/oj-lab-platform/modules/agent/casbin"

judge_model "github.com/oj-lab/oj-lab-platform/models/judge"
problem_model "github.com/oj-lab/oj-lab-platform/models/problem"
user_model "github.com/oj-lab/oj-lab-platform/models/user"
casbin_agent "github.com/oj-lab/oj-lab-platform/modules/agent/casbin"
gorm_agent "github.com/oj-lab/oj-lab-platform/modules/agent/gorm"
minio_agent "github.com/oj-lab/oj-lab-platform/modules/agent/minio"
redis_agent "github.com/oj-lab/oj-lab-platform/modules/agent/redis"

log_module "github.com/oj-lab/oj-lab-platform/modules/log"
)
Expand Down Expand Up @@ -44,6 +44,16 @@ func removeMinioObjects() {
log_module.AppLogger().Info("Remove Minio Objects success")
}

func clearRedis() {
ctx := context.Background()
redis_agent := redis_agent.GetDefaultRedisClient()
err := redis_agent.FlushDB(ctx).Err()
if err != nil {
log_module.AppLogger().WithError(err).Error("Failed to clear redis")
}

log_module.AppLogger().Info("Clear Redis success")
}
func clearDB() {
db := gorm_agent.GetDefaultDB()

Expand All @@ -53,6 +63,8 @@ func clearDB() {
&problem_model.ProblemTag{},
&judge_model.Judge{},
&judge_model.JudgeResult{},
&judge_model.JudgeScoreCache{},
&judge_model.JudgeRankCache{},
"problem_problem_tags",
"casbin_rule",
)
Expand All @@ -61,12 +73,13 @@ func clearDB() {
panic("failed to drop tables")
}

log_module.AppLogger().Info("Clear db success")

log_module.AppLogger().Info("Clear DB success")
}

func main() {
removeMinioObjects()
clearCasbin()
clearRedis()
clearDB()

println("data clean success")
Expand Down
14 changes: 14 additions & 0 deletions cmd/init/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ func initDB() {
&problem_model.Problem{},
&judge_model.Judge{},
&judge_model.JudgeResult{},
&judge_model.JudgeScoreCache{},
&judge_model.JudgeRankCache{},
)
if err != nil {
panic("failed to migrate database")
Expand All @@ -36,8 +38,20 @@ func initDB() {
Account: "anonymous",
Password: func() *string { s := ""; return &s }(),
})

if err != nil {
panic(fmt.Sprintf("failed to create anonymous user: %v", err))
}

_, err = judge_model.CreateJudgeRankCache(db, judge_model.NewJudgeRankCache("root"))
if err != nil {
panic(fmt.Sprintf("failed to create root rankcache: %v", err))
}

_, err = judge_model.CreateJudgeRankCache(db, judge_model.NewJudgeRankCache("anonymous"))
if err != nil {
panic(fmt.Sprintf("failed to create anonymous rankcache: %v", err))
}

log_module.AppLogger().Info("migrate tables ans users success")
}
6 changes: 6 additions & 0 deletions cmd/web_server/handler/judge_result.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,10 @@ func postReportJudgeResult(ginCtx *gin.Context) {
gin_utils.NewInternalError(ginCtx, err.Error())
return
}

err = judge_service.UpsertJudgeCache(ginCtx, judgeUID, verdict)
if err != nil {
gin_utils.NewInternalError(ginCtx, err.Error())
return
}
}
14 changes: 14 additions & 0 deletions models/judge/judge_db.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,20 @@
return &judge, tx.Create(&judge).Error
}

// only count if when accept && accept time < SolvedTime
func GetBeforeSubmission(tx *gorm.DB, judge Judge) (int64, error) {
var count int64
err := tx.Model(&Judge{}).
Where("create_at < ?", judge.CreateAt).
Where("status = ?", JudgeStatusFinished).
Count(&count).Error

Check warning on line 30 in models/judge/judge_db.go

View check run for this annotation

Codecov / codecov/patch

models/judge/judge_db.go#L25-L30

Added lines #L25 - L30 were not covered by tests

if err != nil {
return 0, err

Check warning on line 33 in models/judge/judge_db.go

View check run for this annotation

Codecov / codecov/patch

models/judge/judge_db.go#L32-L33

Added lines #L32 - L33 were not covered by tests
}
return count + 1, err

Check warning on line 35 in models/judge/judge_db.go

View check run for this annotation

Codecov / codecov/patch

models/judge/judge_db.go#L35

Added line #L35 was not covered by tests
}

func GetJudge(tx *gorm.DB, uid uuid.UUID) (*Judge, error) {
judge := Judge{}
err := tx.Model(&Judge{}).
Expand Down
23 changes: 23 additions & 0 deletions models/judge/judge_rank_cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package judge_model

import (
"github.com/oj-lab/oj-lab-platform/models"
user_model "github.com/oj-lab/oj-lab-platform/models/user"
)

// user contest summary rank info
type JudgeRankCache struct {
models.MetaFields
UserAccount string `json:"userAccount" gorm:"primaryKey"`
User user_model.User `json:"user"`
Points int64 `json:"points"`
TotalSubmissions int64 `json:"totalSubmissions"`
}

func NewJudgeRankCache(userAccount string) JudgeRankCache {
return JudgeRankCache{
UserAccount: userAccount,
Points: 0,
TotalSubmissions: 0,

Check warning on line 21 in models/judge/judge_rank_cache.go

View check run for this annotation

Codecov / codecov/patch

models/judge/judge_rank_cache.go#L17-L21

Added lines #L17 - L21 were not covered by tests
}
}
26 changes: 26 additions & 0 deletions models/judge/judge_rank_cache_db.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package judge_model

import (
"github.com/oj-lab/oj-lab-platform/models"
"gorm.io/gorm"
)

func CreateJudgeRankCache(tx *gorm.DB, rankCache JudgeRankCache) (*JudgeRankCache, error) {
rankCache.MetaFields = models.NewMetaFields()
return &rankCache, tx.Create(&rankCache).Error

Check warning on line 10 in models/judge/judge_rank_cache_db.go

View check run for this annotation

Codecov / codecov/patch

models/judge/judge_rank_cache_db.go#L8-L10

Added lines #L8 - L10 were not covered by tests
}

func GetJudgeRankCache(tx *gorm.DB, userAccount string) (*JudgeRankCache, error) {
rankCache := JudgeRankCache{}
err := tx.Model(&JudgeRankCache{}).
Where("user_account = ?", userAccount).
First(&rankCache).Error
if err != nil {
return nil, err

Check warning on line 19 in models/judge/judge_rank_cache_db.go

View check run for this annotation

Codecov / codecov/patch

models/judge/judge_rank_cache_db.go#L13-L19

Added lines #L13 - L19 were not covered by tests
}
return &rankCache, nil

Check warning on line 21 in models/judge/judge_rank_cache_db.go

View check run for this annotation

Codecov / codecov/patch

models/judge/judge_rank_cache_db.go#L21

Added line #L21 was not covered by tests
}

func UpdateJudgeRankCache(tx *gorm.DB, rankCache JudgeRankCache) error {
return tx.Model(&rankCache).Updates(rankCache).Error

Check warning on line 25 in models/judge/judge_rank_cache_db.go

View check run for this annotation

Codecov / codecov/patch

models/judge/judge_rank_cache_db.go#L24-L25

Added lines #L24 - L25 were not covered by tests
}
30 changes: 30 additions & 0 deletions models/judge/judge_score_cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package judge_model

import (
"time"

"github.com/oj-lab/oj-lab-platform/models"
problem_model "github.com/oj-lab/oj-lab-platform/models/problem"
user_model "github.com/oj-lab/oj-lab-platform/models/user"
)

// user contest problem summary score info
type JudgeScoreCache struct {
models.MetaFields
UserAccount string `json:"userAccount" gorm:"primaryKey"`
User user_model.User `json:"user"`
ProblemSlug string `json:"problemSlug" gorm:"primaryKey"`
Problem problem_model.Problem `json:"problem"`
SubmissionCount int64 `json:"submissionCount" gorm:"default:1"` // judge create time < solvetime will be count
IsAccepted bool `json:"isAccepted" gorm:"default:false"`
SolveTime *time.Time `json:"solveAt" gorm:"default:null"` // ac time < solveTime, update submissionCount
}

func NewJudgeScoreCache(userAccount string, problemSlug string) JudgeScoreCache {
return JudgeScoreCache{
UserAccount: userAccount,
ProblemSlug: problemSlug,
SubmissionCount: 1,
IsAccepted: false,
}
}
27 changes: 27 additions & 0 deletions models/judge/judge_score_cache_db.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package judge_model

import (
"github.com/oj-lab/oj-lab-platform/models"
"gorm.io/gorm"
)

func CreateJudgeScoreCache(tx *gorm.DB, scoreCache JudgeScoreCache) (*JudgeScoreCache, error) {
scoreCache.MetaFields = models.NewMetaFields()
return &scoreCache, tx.Create(&scoreCache).Error
}

func GetJudgeScoreCache(tx *gorm.DB, userAccount string, problemSlug string) (*JudgeScoreCache, error) {
scoreCache := JudgeScoreCache{}
err := tx.Model(&JudgeScoreCache{}).
Where("user_account = ?", userAccount).
Where("problem_slug = ?", problemSlug).
First(&scoreCache).Error
if err != nil {
return nil, err

Check warning on line 20 in models/judge/judge_score_cache_db.go

View check run for this annotation

Codecov / codecov/patch

models/judge/judge_score_cache_db.go#L20

Added line #L20 was not covered by tests
}
return &scoreCache, nil
}

func UpdateJudgeScoreCache(tx *gorm.DB, scoreCache JudgeScoreCache) error {
return tx.Model(&scoreCache).Updates(scoreCache).Error
}
49 changes: 49 additions & 0 deletions models/judge/judge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package judge_model
import (
"encoding/json"
"testing"
"time"

problem_model "github.com/oj-lab/oj-lab-platform/models/problem"
user_model "github.com/oj-lab/oj-lab-platform/models/user"
gorm_agent "github.com/oj-lab/oj-lab-platform/modules/agent/gorm"
)

Expand Down Expand Up @@ -46,3 +48,50 @@ func TestJudgeDB(t *testing.T) {
}
t.Logf("%+v\n", string(judgeJson))
}

func TestJudgeScoreCacheDB(t *testing.T) {
db := gorm_agent.GetDefaultDB()

problem := &problem_model.Problem{
Slug: "test-judgeScoreCache-db-problem",
}
var err error
err = problem_model.CreateProblem(db, *problem)
if err != nil {
t.Error(err)
}

user := &user_model.User{
Account: "test-judgeScoreCache-db-user",
}
_, err = user_model.CreateUser(db, *user)
if err != nil {
t.Error(err)
}

judgeScoreCache := NewJudgeScoreCache(user.Account, problem.Slug)
_, err = CreateJudgeScoreCache(db, judgeScoreCache)
if err != nil {
t.Error(err)
}

now := time.Now()
judgeScoreCache.IsAccepted = true
judgeScoreCache.SolveTime = &now
judgeScoreCache.SubmissionCount = 10
err = UpdateJudgeScoreCache(db, judgeScoreCache)
if err != nil {
t.Error(err)
}

newjudgeScoreCache, err := GetJudgeScoreCache(db, user.Account, problem.Slug)
if err != nil {
t.Error(err)
}

judgeScoreCacheJson, err := json.MarshalIndent(newjudgeScoreCache, "", "\t")
if err != nil {
t.Error(err)
}
t.Logf("%+v\n", string(judgeScoreCacheJson))
}
90 changes: 90 additions & 0 deletions services/judge/judge_cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package judge_service

import (
"context"

"github.com/google/uuid"
judge_model "github.com/oj-lab/oj-lab-platform/models/judge"
gorm_agent "github.com/oj-lab/oj-lab-platform/modules/agent/gorm"
)

func UpsertJudgeCache(ctx context.Context, uid uuid.UUID, verdict judge_model.JudgeVerdict) error {
db := gorm_agent.GetDefaultDB()
judge, err := judge_model.GetJudge(db, uid)
if err != nil {
return err

Check warning on line 15 in services/judge/judge_cache.go

View check run for this annotation

Codecov / codecov/patch

services/judge/judge_cache.go#L11-L15

Added lines #L11 - L15 were not covered by tests
}
// log_module.AppLogger().WithField("judge", judge).Debug("getjudge")
var scoreCache *judge_model.JudgeScoreCache
var rankCache *judge_model.JudgeRankCache
rankCache, err = judge_model.GetJudgeRankCache(db, judge.UserAccount)
if err != nil {
return err

Check warning on line 22 in services/judge/judge_cache.go

View check run for this annotation

Codecov / codecov/patch

services/judge/judge_cache.go#L18-L22

Added lines #L18 - L22 were not covered by tests
}

extraPoint := 0
for {
scoreCache, err = judge_model.GetJudgeScoreCache(db, judge.UserAccount, judge.ProblemSlug)
if err != nil {

Check warning on line 28 in services/judge/judge_cache.go

View check run for this annotation

Codecov / codecov/patch

services/judge/judge_cache.go#L25-L28

Added lines #L25 - L28 were not covered by tests
// previous empty
// log_module.AppLogger().Debug("previous empty")
scoreCache := judge_model.NewJudgeScoreCache(judge.UserAccount, judge.ProblemSlug)
if verdict == judge_model.JudgeVerdictAccepted {
extraPoint = 1
scoreCache.IsAccepted = true
scoreCache.SolveTime = judge.CreateAt

Check warning on line 35 in services/judge/judge_cache.go

View check run for this annotation

Codecov / codecov/patch

services/judge/judge_cache.go#L31-L35

Added lines #L31 - L35 were not covered by tests
}
_, err := judge_model.CreateJudgeScoreCache(db, scoreCache)
if err != nil { // create fail, get data again and continue the update logic.
continue

Check warning on line 39 in services/judge/judge_cache.go

View check run for this annotation

Codecov / codecov/patch

services/judge/judge_cache.go#L37-L39

Added lines #L37 - L39 were not covered by tests
}

// create success
rankCache.Points += int64(extraPoint)
rankCache.TotalSubmissions += 1
err = judge_model.UpdateJudgeRankCache(db, *rankCache)
if err != nil {
return err

Check warning on line 47 in services/judge/judge_cache.go

View check run for this annotation

Codecov / codecov/patch

services/judge/judge_cache.go#L43-L47

Added lines #L43 - L47 were not covered by tests
}
return nil
} else {
break

Check warning on line 51 in services/judge/judge_cache.go

View check run for this annotation

Codecov / codecov/patch

services/judge/judge_cache.go#L49-L51

Added lines #L49 - L51 were not covered by tests
}
}

// log_module.AppLogger().WithField("scoreCache", scoreCache).Debug("get scoreCache")

// previous no ac || current more early
// need to update
if !scoreCache.IsAccepted || judge.CreateAt.Before(*scoreCache.SolveTime) {
if !scoreCache.IsAccepted {
extraPoint = 1

Check warning on line 61 in services/judge/judge_cache.go

View check run for this annotation

Codecov / codecov/patch

services/judge/judge_cache.go#L59-L61

Added lines #L59 - L61 were not covered by tests
}
preSubmissionCount := scoreCache.SubmissionCount
if verdict == judge_model.JudgeVerdictAccepted {
scoreCache.SubmissionCount, err = judge_model.GetBeforeSubmission(db, *judge) // rescan to count previous finished
if err != nil {
return err

Check warning on line 67 in services/judge/judge_cache.go

View check run for this annotation

Codecov / codecov/patch

services/judge/judge_cache.go#L63-L67

Added lines #L63 - L67 were not covered by tests
}
scoreCache.IsAccepted = true
rankCache.Points = rankCache.Points + int64(extraPoint)
scoreCache.SolveTime = judge.CreateAt
} else {
scoreCache.SubmissionCount += 1

Check warning on line 73 in services/judge/judge_cache.go

View check run for this annotation

Codecov / codecov/patch

services/judge/judge_cache.go#L69-L73

Added lines #L69 - L73 were not covered by tests
}
rankCache.TotalSubmissions += scoreCache.SubmissionCount - preSubmissionCount

Check warning on line 75 in services/judge/judge_cache.go

View check run for this annotation

Codecov / codecov/patch

services/judge/judge_cache.go#L75

Added line #L75 was not covered by tests
// log_module.AppLogger().WithField("scoreCache", scoreCache).Debug("update scoreCache")

err = judge_model.UpdateJudgeScoreCache(db, *scoreCache)
if err != nil {
return err

Check warning on line 80 in services/judge/judge_cache.go

View check run for this annotation

Codecov / codecov/patch

services/judge/judge_cache.go#L78-L80

Added lines #L78 - L80 were not covered by tests
}

err = judge_model.UpdateJudgeRankCache(db, *rankCache)
if err != nil {
return err

Check warning on line 85 in services/judge/judge_cache.go

View check run for this annotation

Codecov / codecov/patch

services/judge/judge_cache.go#L83-L85

Added lines #L83 - L85 were not covered by tests
}
}
// if no early, no need update, just a query
return nil

Check warning on line 89 in services/judge/judge_cache.go

View check run for this annotation

Codecov / codecov/patch

services/judge/judge_cache.go#L89

Added line #L89 was not covered by tests
}
Loading
Loading