-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathstore.go
151 lines (128 loc) · 2.57 KB
/
store.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
package crawler
import (
"errors"
"net/url"
"sync"
)
var ErrItemNotFound = errors.New("memstore: item is not found")
// Store stores all URLs.
type Store interface {
Exist(u *url.URL) (bool, error)
Get(u *url.URL) (*URL, error)
GetDepth(u *url.URL) (int, error)
GetFunc(u *url.URL, f func(*URL)) error
PutNX(u *URL) (bool, error)
Complete(u *url.URL) error
Update(u *URL) error
UpdateFunc(u *url.URL, f func(*URL)) error
IncVisitCount() error
IsFinished() (bool, error)
Close() error
}
type PersistableStore interface {
Store
// Recover send all unfinished URLs to ch.
Recover(ch chan<- *url.URL) error
}
type MemStore struct {
sync.RWMutex
m map[string]*URL
NumURL int32
NumDone int32
NumVisit int32
NumError int32
}
func NewMemStore() *MemStore {
return &MemStore{
m: make(map[string]*URL),
}
}
func (p *MemStore) Exist(u *url.URL) (bool, error) {
p.RLock()
defer p.RUnlock()
_, ok := p.m[u.String()]
return ok, nil
}
func (p *MemStore) Get(u *url.URL) (uu *URL, err error) {
p.RLock()
entry, present := p.m[u.String()]
if present {
uu = entry.clone()
} else {
err = errors.New("memstore: item is not found")
}
p.RUnlock()
return
}
func (p *MemStore) GetFunc(u *url.URL, f func(*URL)) error {
p.RLock()
defer p.RUnlock()
entry, present := p.m[u.String()]
if !present {
return errors.New("memstore: item is not found")
}
f(entry.clone())
return nil
}
func (p *MemStore) GetDepth(u *url.URL) (int, error) {
p.RLock()
defer p.RUnlock()
if uu, ok := p.m[u.String()]; ok {
return uu.Depth, nil
}
return 0, ErrItemNotFound
}
func (p *MemStore) PutNX(u *URL) (bool, error) {
p.Lock()
defer p.Unlock()
if _, ok := p.m[u.URL.String()]; ok {
return false, nil
}
p.m[u.URL.String()] = u.clone()
p.NumURL++
return true, nil
}
func (p *MemStore) UpdateFunc(u *url.URL, f func(*URL)) error {
p.Lock()
defer p.Unlock()
uu, ok := p.m[u.String()]
if !ok {
return ErrItemNotFound
}
f(uu)
return nil
}
func (p *MemStore) Update(u *URL) error {
return p.UpdateFunc(&u.URL, func(uu *URL) {
uu.Update(u)
})
}
func (p *MemStore) Complete(u *url.URL) error {
p.Lock()
defer p.Unlock()
uu, ok := p.m[u.String()]
if !ok {
return ErrItemNotFound
}
uu.Done = true
p.NumDone++
return nil
}
func (p *MemStore) IncVisitCount() error {
p.Lock()
p.NumVisit++
p.Unlock()
return nil
}
func (p *MemStore) IncErrorCount() error {
p.Lock()
p.NumError++
p.Unlock()
return nil
}
func (p *MemStore) IsFinished() (bool, error) {
p.RLock()
defer p.RUnlock()
return p.NumDone >= p.NumURL, nil
}
func (p *MemStore) Close() error { return nil }