github.com/hanwen/go-fuse@v1.0.0/fuse/nodefs/handle.go (about)

     1  // Copyright 2016 the Go-FUSE Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package nodefs
     6  
     7  import (
     8  	"log"
     9  	"sync"
    10  )
    11  
    12  // HandleMap translates objects in Go space to 64-bit handles that can
    13  // be given out to -say- the linux kernel as NodeIds.
    14  //
    15  // The 32 bits version of this is a threadsafe wrapper around a map.
    16  //
    17  // To use it, include "handled" as first member of the structure
    18  // you wish to export.
    19  //
    20  // This structure is thread-safe.
    21  type handleMap interface {
    22  	// Register stores "obj" and returns a unique (NodeId, generation) tuple.
    23  	Register(obj *handled) (handle, generation uint64)
    24  	Count() int
    25  	// Decode retrieves a stored object from its 64-bit handle.
    26  	Decode(uint64) *handled
    27  	// Forget decrements the reference counter for "handle" by "count" and drops
    28  	// the object if the refcount reaches zero.
    29  	// Returns a boolean whether the object was dropped and the object itself.
    30  	Forget(handle uint64, count int) (bool, *handled)
    31  	// Handle gets the object's NodeId.
    32  	Handle(obj *handled) uint64
    33  	// Has checks if NodeId is stored.
    34  	Has(uint64) bool
    35  }
    36  
    37  type handled struct {
    38  	handle     uint64
    39  	generation uint64
    40  	count      int
    41  }
    42  
    43  func (h *handled) verify() {
    44  	if h.count < 0 {
    45  		log.Panicf("negative lookup count %d", h.count)
    46  	}
    47  	if (h.count == 0) != (h.handle == 0) {
    48  		log.Panicf("registration mismatch: lookup %d id %d", h.count, h.handle)
    49  	}
    50  }
    51  
    52  const _ALREADY_MSG = "Object already has a handle"
    53  
    54  ////////////////////////////////////////////////////////////////
    55  // portable version using 32 bit integers.
    56  
    57  type portableHandleMap struct {
    58  	sync.RWMutex
    59  	// The generation counter is incremented each time a NodeId is reused,
    60  	// hence the (NodeId, Generation) tuple is always unique.
    61  	generation uint64
    62  	// Number of currently used handles
    63  	used int
    64  	// Array of Go objects indexed by NodeId
    65  	handles []*handled
    66  	// Free slots in the "handles" array
    67  	freeIds []uint64
    68  }
    69  
    70  func newPortableHandleMap() *portableHandleMap {
    71  	return &portableHandleMap{
    72  		// Avoid handing out ID 0 and 1.
    73  		handles: []*handled{nil, nil},
    74  	}
    75  }
    76  
    77  func (m *portableHandleMap) Register(obj *handled) (handle, generation uint64) {
    78  	m.Lock()
    79  	defer m.Unlock()
    80  	// Reuse existing handle
    81  	if obj.count != 0 {
    82  		obj.count++
    83  		return obj.handle, obj.generation
    84  	}
    85  	// Create a new handle number or recycle one on from the free list
    86  	if len(m.freeIds) == 0 {
    87  		obj.handle = uint64(len(m.handles))
    88  		m.handles = append(m.handles, obj)
    89  	} else {
    90  		obj.handle = m.freeIds[len(m.freeIds)-1]
    91  		m.freeIds = m.freeIds[:len(m.freeIds)-1]
    92  		m.handles[obj.handle] = obj
    93  	}
    94  	// Increment generation number to guarantee the (handle, generation) tuple
    95  	// is unique
    96  	m.generation++
    97  	m.used++
    98  	obj.generation = m.generation
    99  	obj.count++
   100  
   101  	return obj.handle, obj.generation
   102  }
   103  
   104  func (m *portableHandleMap) Handle(obj *handled) (h uint64) {
   105  	m.RLock()
   106  	if obj.count == 0 {
   107  		h = 0
   108  	} else {
   109  		h = obj.handle
   110  	}
   111  	m.RUnlock()
   112  	return h
   113  }
   114  
   115  func (m *portableHandleMap) Count() int {
   116  	m.RLock()
   117  	c := m.used
   118  	m.RUnlock()
   119  	return c
   120  }
   121  
   122  func (m *portableHandleMap) Decode(h uint64) *handled {
   123  	m.RLock()
   124  	v := m.handles[h]
   125  	m.RUnlock()
   126  	return v
   127  }
   128  
   129  func (m *portableHandleMap) Forget(h uint64, count int) (forgotten bool, obj *handled) {
   130  	m.Lock()
   131  	obj = m.handles[h]
   132  	obj.count -= count
   133  	if obj.count < 0 {
   134  		log.Panicf("underflow: handle %d, count %d, object %d", h, count, obj.count)
   135  	} else if obj.count == 0 {
   136  		m.handles[h] = nil
   137  		m.freeIds = append(m.freeIds, h)
   138  		m.used--
   139  		forgotten = true
   140  		obj.handle = 0
   141  	}
   142  	m.Unlock()
   143  	return forgotten, obj
   144  }
   145  
   146  func (m *portableHandleMap) Has(h uint64) bool {
   147  	m.RLock()
   148  	ok := m.handles[h] != nil
   149  	m.RUnlock()
   150  	return ok
   151  }