github.com/slspeek/camlistore_namedsearch@v0.0.0-20140519202248-ed6f70f7721a/pkg/fs/debug.go (about) 1 // +build linux darwin 2 3 /* 4 Copyright 2013 Google Inc. 5 6 Licensed under the Apache License, Version 2.0 (the "License"); 7 you may not use this file except in compliance with the License. 8 You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 See the License for the specific language governing permissions and 16 limitations under the License. 17 */ 18 19 package fs 20 21 import ( 22 "bytes" 23 "fmt" 24 "os" 25 "strconv" 26 27 "camlistore.org/pkg/types" 28 29 "camlistore.org/third_party/bazil.org/fuse" 30 "camlistore.org/third_party/bazil.org/fuse/fs" 31 ) 32 33 // If TrackStats is true, statistics are kept on operations. 34 var TrackStats bool 35 36 func init() { 37 TrackStats, _ = strconv.ParseBool(os.Getenv("CAMLI_TRACK_FS_STATS")) 38 } 39 40 var ( 41 mutFileOpen = newStat("mutfile-open") 42 mutFileOpenError = newStat("mutfile-open-error") 43 mutFileOpenRO = newStat("mutfile-open-ro") 44 mutFileOpenRW = newStat("mutfile-open-rw") 45 roFileOpen = newStat("rofile-open") 46 roFileOpenError = newStat("rofile-open-error") 47 ) 48 49 var statByName = map[string]*stat{} 50 51 func newStat(name string) *stat { 52 if statByName[name] != nil { 53 panic("duplicate registraton of " + name) 54 } 55 s := &stat{name: name} 56 statByName[name] = s 57 return s 58 } 59 60 // A stat is a wrapper around an atomic int64, as is a fuse.Node 61 // exporting that data as a decimal. 62 type stat struct { 63 n types.AtomicInt64 64 name string 65 } 66 67 func (s *stat) Incr() { 68 if TrackStats { 69 s.n.Add(1) 70 } 71 } 72 73 func (s *stat) content() []byte { 74 var buf bytes.Buffer 75 fmt.Fprintf(&buf, "%d", s.n.Get()) 76 buf.WriteByte('\n') 77 return buf.Bytes() 78 } 79 80 func (s *stat) Attr() fuse.Attr { 81 return fuse.Attr{ 82 Mode: 0400, 83 Uid: uint32(os.Getuid()), 84 Gid: uint32(os.Getgid()), 85 Size: uint64(len(s.content())), 86 Mtime: serverStart, 87 Ctime: serverStart, 88 Crtime: serverStart, 89 } 90 } 91 92 func (s *stat) Read(req *fuse.ReadRequest, res *fuse.ReadResponse, intr fs.Intr) fuse.Error { 93 c := s.content() 94 if req.Offset > int64(len(c)) { 95 return nil 96 } 97 c = c[req.Offset:] 98 size := req.Size 99 if size > len(c) { 100 size = len(c) 101 } 102 res.Data = make([]byte, size) 103 copy(res.Data, c) 104 return nil 105 } 106 107 // A statsDir FUSE directory node is returned by root.go, by opening 108 // ".camli_fs_stats" in the root directory. 109 type statsDir struct{} 110 111 func (statsDir) Attr() fuse.Attr { 112 return fuse.Attr{ 113 Mode: os.ModeDir | 0700, 114 Uid: uint32(os.Getuid()), 115 Gid: uint32(os.Getgid()), 116 } 117 } 118 119 func (statsDir) ReadDir(intr fs.Intr) (ents []fuse.Dirent, err fuse.Error) { 120 for k := range statByName { 121 ents = append(ents, fuse.Dirent{Name: k}) 122 } 123 return 124 } 125 126 func (statsDir) Lookup(req *fuse.LookupRequest, res *fuse.LookupResponse, intr fs.Intr) (fs.Node, fuse.Error) { 127 name := req.Name 128 s, ok := statByName[name] 129 if !ok { 130 return nil, fuse.ENOENT 131 } 132 return s, nil 133 }