-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmain.go
127 lines (107 loc) · 2.89 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package main
import (
"database/sql"
"math/rand"
"fmt"
"log"
"net/http"
"os"
"sync"
"strconv"
"strings"
_ "github.com/go-sql-driver/mysql"
)
var dbs []*sql.DB
var mu sync.Mutex
var counter int64
var filename string = "counter.txt"
func init(){
dbUser := os.Getenv("DBUSER")
dbPass := os.Getenv("DBPASS")
dbHost := "127.0.0.1:3300"
shard1 := fmt.Sprintf("%s:%s@tcp(%s)/blog_shard1", dbUser, dbPass, dbHost)
shard2 := fmt.Sprintf("%s:%s@tcp(%s)/blog_shard2", dbUser, dbPass, dbHost)
db1, _ := sql.Open("mysql", shard1)
db2, _ := sql.Open("mysql", shard2)
dbs = append(dbs, db1)
dbs = append(dbs, db2)
}
func saveCounter(counter int64){
data := strconv.FormatInt(counter, 10)
os.WriteFile(filename, []byte(data), 0644)
}
func loadCounter() int64{
data, err := os.ReadFile(filename)
if err != nil{
panic(err)
}
id, err := strconv.ParseInt(string(data), 10, 64)
if err != nil{
panic(err)
}
return id
}
func generateBlogID() int64{
mu.Lock()
id := counter
counter++
if counter%10 == 0{
saveCounter(id)
}
mu.Unlock()
return id
}
func getShard(userID int) *sql.DB{
idx := userID % len(dbs)
return dbs[idx]
}
func createBlogHandler(w http.ResponseWriter, r *http.Request){
userID := rand.Intn(10)
blogID := generateBlogID()
title := fmt.Sprintf("Blog-%d",blogID)
content := fmt.Sprintf("This is the content of blog_%d.", blogID)
db := getShard(userID)
_, err := db.Exec("INSERT into blogs (blog_id, user_id, title, content) VALUES (?, ?, ?, ?)", blogID, userID, title, content)
if err != nil{
http.Error(w, "Failed to insert blog", http.StatusInternalServerError)
return
}
fmt.Fprintf(w, "Blog created with ID: %d on shard for user %d\n", blogID, userID)
}
func fetchBlogHandler(w http.ResponseWriter, r *http.Request){
// extract userId from the url
parts := strings.Split(r.URL.Path, "/")
if len(parts) < 3 {
http.Error(w, "Invalid URL", http.StatusBadRequest)
}
userIDStr := strings.TrimPrefix(parts[2], "userid-")
userID, err := strconv.Atoi(userIDStr)
if err != nil {
http.Error(w, "Invalid user ID", http.StatusBadRequest)
return
}
db := getShard(userID)
rows, err := db.Query("SELECT blog_id, title, content FROM blogs WHERE user_id = ?", userID)
if err != nil {
http.Error(w, "Failed to fetch blogs", http.StatusInternalServerError)
return
}
defer rows.Close()
// print the values on the webpage
for rows.Next() {
var blogID int64
var title, content string
if err := rows.Scan(&blogID, &title, &content); err != nil {
http.Error(w, "Failed to scan row", http.StatusInternalServerError)
return
}
fmt.Fprintf(w, "Blog ID: %d, Title: %s, Content: %s\n", blogID, title, content)
}
}
func main(){
counter = loadCounter() + 100 //maintain persistence
http.HandleFunc("/create_blog", createBlogHandler)
http.HandleFunc("/fetch_blog/", fetchBlogHandler)
fmt.Println("Starting server at 8080...")
log.Fatal(http.ListenAndServe(":8000", nil))
}