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  }