-
Notifications
You must be signed in to change notification settings - Fork 9
/
main.go
223 lines (187 loc) · 4.65 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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
/*
cn 12306 数据结构
*/
package main
import (
"fmt"
"strconv"
"sync"
"time"
)
var (
serverId int //服务编号
baseDate int = int(time.Date(2012, 1, 0, 0, 0, 0, 0, time.UTC).Unix() / (60 * 60 * 24))
maxSearchCount int = 10 //查询剩余车票返回的最大值
maxLength int = 62 //车次最多经停站数
)
var (
trains map[int]*Train
lock sync.Mutex
)
// 车次+日期
type Train struct {
snow *snow //Id生产器
lock sync.RWMutex //锁
train int //车次
date int //日期
data []uint64 //座位数据
config *TrainConfig //配置
dbAddress string //redis 的地址
dbKey string //redis hashset的key
dbConnect interface{} //redis connection
}
func newTrain(train, date int) *Train {
config := getTrainConfig(train)
t := &Train{
snow: newSnow(train, serverId),
train: train,
date: date,
data: make([]uint64, config.length),
config: config,
dbKey: "hashset_" + strconv.Itoa((train<<16)|date),
dbAddress: "db address",
dbConnect: "db connection"}
return t
}
// 车次一些配置数据
type TrainConfig struct {
length int //座位数
_ string //其他
}
func getTrainConfig(train int) *TrainConfig {
return &TrainConfig{length: maxLength}
}
// 订单
type Order struct {
id uint64 //订单编号
user int64 //用户编号
index int //座位编号
train int //车次
date int //日期
stamp int64 //时间戳
}
func init() {
serverId = 123
trains = make(map[int]*Train, 1000)
fmt.Println("init", "server id", serverId, "baseDate", baseDate)
}
// 获取车次数据
func getTrain(train, date int) (*Train, bool) {
key := (train << 16) | date
t, ok := trains[key]
return t, ok
}
// 一次只查询一个车次,可以很容易的扩展到查询多个车次
func search(train, date int, start, end uint8) (count int) {
if t, ok := getTrain(train, date); ok {
return t.search(start, end)
}
return 0
}
// 一次只预订一个座位,可以很容易扩展为预订多个
func order(user int64, train, date int, start, end uint8) (order Order, ok bool) {
if t, ok := getTrain(train, date); ok {
return t.order(user, start, end)
}
return
}
// 定时增加车次数据
func addTrain(train, date int) {
key := (train << 16) | date
lock.Lock()
defer lock.Unlock()
t := newTrain(train, date)
trains[key] = t
}
// 查询是否有票
func (t *Train) search(start, end uint8) (count int) {
data := t.data
var mask uint64 = (1<<(end-start) - 1) << (start)
for _, d := range data {
if d&mask == 0 {
count++
}
if count > maxSearchCount {
break
}
}
return count
}
// 预订
func (t *Train) order(user int64, start, end uint8) (order Order, ok bool) {
var mask uint64 = (1<<(end-start) - 1) << (start)
t.lock.Lock()
defer t.lock.Unlock()
data := t.data
length := t.config.length
for i := 0; i < length; i++ {
if data[i]&mask != 0 {
continue
}
//持久化,处理队列
order = Order{id: t.snow.nextInt(), user: user, index: i, train: t.train, date: t.date, stamp: time.Now().Unix()}
data[i] = data[i] | mask
return order, true
}
return
}
// 将日期转化为整数
func formatDate(t time.Time) int {
return int(t.Unix()/(60*60*24)) - baseDate
}
func main() {
date := formatDate(time.Now())
for i := 0; i < 1024; i++ {
addTrain(i, date)
}
testSearch()
}
func testSearch() {
total := 1000 * 1000
date := formatDate(time.Now())
start := time.Now()
var count int
for i := 0; i < total; i++ {
count = search(total/1000, date, 3, 17)
}
end := time.Now()
fmt.Println("start", start)
fmt.Println("end", end)
fmt.Println("duration", end.Sub(start).Nanoseconds()/1000000)
fmt.Println("search result", count)
}
// id生成器
type snow struct {
lock sync.Mutex
base int64
stamp int64 //上次生成编号的时间戳,24位,分钟为单位
train int //车次编号,13位 = 1024*8
server int //服务编号,9位 = 512
sequence int //上次生成编号,18位 = 1024*256
mask int
}
func newSnow(train, server int) *snow {
snow := &snow{
train: train,
server: server,
base: time.Date(2012, 1, 0, 0, 0, 0, 0, time.UTC).Unix() / 60,
mask: -1 ^ (-1 << 18)}
return snow
}
func (snow *snow) nextInt() uint64 {
snow.lock.Lock()
defer snow.lock.Unlock()
ts := time.Now().Unix()/60 - snow.base
if ts == snow.stamp {
snow.sequence = (snow.sequence + 1) & snow.mask
if snow.sequence == 0 {
panic("error:overflow")
}
} else {
snow.sequence = 0
}
snow.stamp = ts
id := (uint64(snow.stamp) << (18 + 9 + 13)) | (uint64(snow.train) << (9 + 18)) |
(uint64(snow.server) << 18) | (uint64(snow.sequence))
return id
}