/
serve.go
147 lines (127 loc) · 3.66 KB
/
serve.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
// Copyright 2017 The Upspin Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"expvar"
"flag"
"net/http"
"os"
"path/filepath"
"upspin.io/config"
"upspin.io/dir/dircache"
"upspin.io/flags"
"upspin.io/log"
"upspin.io/rpc/dirserver"
"upspin.io/rpc/local"
"upspin.io/rpc/storeserver"
"upspin.io/store/storecache"
"upspin.io/upspin"
// Load required transports
_ "upspin.io/transports"
// Load useful packers
_ "upspin.io/pack/ee"
_ "upspin.io/pack/eeintegrity"
_ "upspin.io/pack/plain"
)
var (
writethrough = flag.Bool("writethrough", false, "make storage cache writethrough")
)
func serve(cfg upspin.Config, addr string) (<-chan error, error) {
cachedCfg := cfg
uncachedCfg := config.SetCacheEndpoint(cfg, upspin.Endpoint{})
// Calculate limits.
maxRefBytes := (9 * (flags.CacheSize)) / 10
maxLogBytes := maxRefBytes / 9
myCacheDir := filepath.Join(flags.CacheDir, string(cfg.UserName()))
// Link old structure cache files into the new structure.
relocate(flags.CacheDir, myCacheDir)
sc, blockFlusher, err := storecache.New(uncachedCfg, myCacheDir, maxRefBytes, *writethrough)
if err != nil {
return nil, err
}
ss := storeserver.New(uncachedCfg, sc, "")
dc, err := dircache.New(uncachedCfg, cachedCfg, myCacheDir, maxLogBytes, blockFlusher)
if err != nil {
return nil, err
}
ds := dirserver.New(uncachedCfg, dc, "")
ln, err := local.Listen("tcp", addr)
if err != nil {
return nil, err
}
// Use our own ServerMux so that we can run in the same
// process as a server using the default one.
mux := &http.ServeMux{}
httpServer := &http.Server{
Handler: mux,
ErrorLog: log.NewStdLogger(log.Debug),
}
mux.Handle("/api/Store/", ss)
mux.Handle("/api/Dir/", ds)
mux.Handle("/debug/vars", expvar.Handler())
done := make(chan error)
go func() {
done <- httpServer.Serve(ln)
}()
return done, nil
}
// relocate links the old directory contents one level down into a
// user specific directory. By linking the files one at a time rather
// than linking or renaming the directories, we cause the least interference
// between old and new worlds should an old server still be running.
//
// TODO(p): when everyone has had a chance to convert, replace this with
// a routine that removes the old structure.
func relocate(old, new string) {
if _, err := os.Stat(new); err == nil || !os.IsNotExist(err) {
// Already done, do nothing.
return
}
if err := os.MkdirAll(new, 0700); err != nil {
log.Debug.Printf("cacheserver/relocate: %s", err)
return
}
walkAndMove(old, new, "storewritebackqueue", nil)
walkAndMove(old, new, "storecache", nil)
walkAndMove(old, new, "dircache", nil)
}
// walkAndMove links old files into new structure.
func walkAndMove(oldDir, newDir, name string, info os.FileInfo) {
old := filepath.Join(oldDir, name)
new := filepath.Join(newDir, name)
if info == nil {
var err error
info, err = os.Stat(old)
if err != nil {
log.Debug.Printf("cacheserver/walkAndMove: %s", err)
return
}
}
// Link files into new directory structure.
if !info.Mode().IsDir() {
if err := os.Link(old, new); err != nil {
log.Debug.Printf("cacheserver/walkAndMove: %s", err)
}
return
}
if err := os.MkdirAll(new, 0700); err != nil {
log.Debug.Printf("cacheserver/walkAndMove: %s", err)
return
}
// Read and descend directories.
f, err := os.Open(old)
if err != nil {
log.Debug.Printf("cacheserver/walkAndMove: %s", err)
return
}
infos, err := f.Readdir(0)
f.Close()
if err != nil {
log.Debug.Printf("cacheserver/walkAndMove: %s", err)
return
}
for _, i := range infos {
walkAndMove(old, new, i.Name(), i)
}
}