diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cf9949d --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.test +.DS_Store +chainsaw +Gopkg.lock +pkg/ +vendor/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1606579 --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +SHELL := /bin/bash + +.PHONY: help + +help: ## Show this help. + @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-40s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) + +deps: ## Install dependencies + go get -u github.com/golang/dep/cmd/dep + go get -u github.com/go-sql-driver/mysql + +tests: ## Run tests + go test -v ./... + +build: ## Build binary for local operating system + go build -o chainsaw main.go diff --git a/main.go b/main.go new file mode 100644 index 0000000..1f59b70 --- /dev/null +++ b/main.go @@ -0,0 +1,71 @@ +package main + +import ( + "fmt" + "time" + "strconv" +) + +type Chunk struct { + Count uint64 // Rows in table. + Delta uint64 // Delta value. + Total uint64 // Count + delta. + Index uint64 // Number of chunks. + Steps uint64 // Numbers of chunks. + Length uint64 // Length of chunk. + Percentage uint64 // Percentage overall process. + Sleep time.Duration // Wait between chunk and chunk. + Start uint64 // Start chunk number. + End uint64 // End chunk number. (Not use yet) + Remain uint64 // Remains chunks until finish. + StartTime time.Time // Start each chunk. + EndTime time.Time // End each chunk. + Duration time.Duration // Duration time between start and end duration. + ETA time.Duration // Estimated time of arrival to complete overall process. +} + +func main() { + c := Chunk{Count: 1000, Delta: 0, Length: 100, Start: 1, Sleep: 1 * time.Second} + c.Loop(func(){ + time.Sleep(1 * time.Second) + }) +} + +func (c *Chunk) Calculate() { + c.Total = c.Count + c.Delta + c.Steps = c.Total / c.Length + c.Percentage = ((100 * c.Index) / c.Total) + c.Duration = c.EndTime.Sub(c.StartTime) + c.Remain = (c.Total - c.Index) / c.Length + c.ETA = time.Duration(c.Remain) * c.Duration +} + +func (c *Chunk) Loop(f interface{}) { + c.Calculate() + for i := c.Start; i <= c.Total; i++ { + if i % c.Length == 0 { + c.StartTime = time.Now() + + f.(func())() + + time.Sleep(c.Sleep) + + c.EndTime = time.Now() + c.Index = i + c.Calculate() + c.Log() + } + } +} + +func (c *Chunk) Log() { + fmt.Printf("%*d %*d/%d %3d%% %.fs\n", IntLength(c.Steps - 1), c.Remain, IntLength(c.Total), c.Index, c.Total, c.Percentage, c.ETA.Seconds()) +} + +func IntLength(v uint64) int { + return len(Int64ToString(v)) +} + +func Int64ToString(v uint64) string { + return strconv.FormatUint(v, 10) +} diff --git a/main_test.go b/main_test.go new file mode 100644 index 0000000..643dc04 --- /dev/null +++ b/main_test.go @@ -0,0 +1,80 @@ +package main_test + +import ( + "fmt" + "testing" + "os" + "database/sql" + + _ "github.com/go-sql-driver/mysql" + + "github.com/swapbyt3s/chainsaw" +) + +var db *sql.DB +var err error + +func TestMain(t *testing.M) { + db, err = sql.Open("mysql", "root:admin@tcp(127.0.0.1:3306)/") + if err != nil { + panic(err.Error()) + } + defer db.Close() + + setupDatabase() + + code := t.Run() + + os.Exit(code) +} + +func setupDatabase() { + migrations := []string{ + "DROP DATABASE IF EXISTS demo_test;", + "CREATE DATABASE IF NOT EXISTS demo_test;", + "USE demo_test;", + `CREATE TABLE IF NOT EXISTS demo_test.foo ( + id int NOT NULL auto_increment, + value char(32) NOT NULL, + token char(32), + PRIMARY KEY (id) +);`, + } + + for i := 1; i <= 100; i++ { + migrations = append(migrations, fmt.Sprintf("INSERT INTO demo_test.foo (value) VALUES (MD5('%d'));", i)) + } + + for _, migration := range migrations { + _, err := db.Query(migration) + if err != nil { + panic(err.Error()) + } + } + +} + +//func TestSomeFeature(t *testing.T) { +// rows, err := db.Query("SELECT id, value FROM demo_test.foo") +// if err != nil { +// panic(err.Error()) +// } +// +// for rows.Next() { +// var id int +// var val string +// +// if err := rows.Scan(&id, &val); err != nil { +// panic(err) +// } +// +// fmt.Printf("%d\t%s\n", id, val) +// } +//} + +func TestChunkCalculate(t *testing.T) { + c := main.Chunk{Count: 1000, Delta: 100, Length: 100, Index: 550} + c.Calculate() + fmt.Printf("%d\n", c.Percentage) + fmt.Printf("%d\n", c.Steps) +}