Exemple #1
0
  def _generatePath(self, fusepath, opcodes=None):
    '''
    Return the path to use for all file operations, based upon the current state
    of the world generated by _genCacheOpcodes.

    Returns:
      None

    Raises:
      Nothing
    '''

    if opcodes == None:
      opcodes = self._genCacheOpcodes(fusepath)

    self._debug('Opcodes are: %s' % opcodes)

    for opcode in opcodes:
      if opcode == 'enoent':
        self._debug('ENOENT on %s' % fusepath)
        raise OSError(errno.ENOENT, os.strerror(errno.ENOENT))
      if opcode == 'use-fs':
        fspath = tsumufs.fsPathOf(fusepath)
        self._debug('Returning fs path for %s -> %s' % (fusepath, fspath))
        return fspath
      if opcode == 'use-cache':
        cachepath = tsumufs.cachePathOf(fusepath)
        self._debug('Returning cache path for %s -> %s' % (fusepath, cachepath))
        return cachepath
Exemple #2
0
  def _cacheDir(self, fusepath):
    '''
    Cache the directory referenced by path.

    If the directory should not be cached to disk (as specified in the
    cachespec) then only the contents of the directory hash table will
    be stored in the _cachedFiles hash.

    Returns:
      None

    Raises:
      OSError - when an error operating on the filesystem occurs.
    '''

    self.lockFile(fusepath)
    
    try:
      fspath    = tsumufs.fsPathOf(fusepath)
      cachepath = tsumufs.cachePathOf(fusepath)

      self._debug('fspath = %s' % fspath)
      self._debug('cachepath = %s' % cachepath)

      if fusepath == '/':
        self._debug('Asking to cache root -- skipping the cache to '
                    'disk operation, but caching data in memory.')

      else:
        try:
          os.mkdir(cachepath)
        except OSError, e:
          # Skip EEXIST errors -- if it already exists, it may have files in it
          # already. Simply copy the stat and chown it again, then cache the
          # listdir operation as well.

          if e.errno != errno.EEXIST:
            raise

      # If activated, populating database will compare the filesystem dirents
      # to the database dirents, and add to database any files that could be
      # created bypassing the CouchedFilesystem api, directly on the filesystem.
      # The performance overhead raised by this operation increase when the number
      # of file to add to database is higher.
      if tsumufs.populateDb:
        try:
          self._debug('Discovering directory %s contents and populate database.' % fusepath)
          dirents = [ doc.filename for doc in tsumufs.fsOverlay.listdir(fusepath) ]

          for filename in os.listdir(fspath):
            if filename not in dirents:
              tsumufs.fsOverlay.populate(os.path.join(fusepath, filename))

        except OSError, e:
          self._debug('Cannot list directory %s (%s)' % (fusepath, e.strerror))
Exemple #3
0
    def write(self, new_data, offset):

        self._debug("opcode: write | path: %s | offset: %d | buf: %s" % (self._path, offset, repr(new_data)))

        # Three cases here:
        #   - The file didn't exist prior to our write.
        #   - The file existed, but was extended.
        #   - The file existed, and an existing block was overwritten.

        fspath = tsumufs.fsPathOf(self._path)
        statgoo = self._manager.statFile(self._path)

        if not self._isNewFile:
            self._debug("Reading offset %d, length %d from %s." % (offset, len(new_data), self._path))
            old_data = self._manager.readFile(self._path, offset, len(new_data), os.O_RDONLY)
            self._debug("From cacheManager.readFile got %s" % repr(old_data))

            # Pad missing chunks on the old_data stream with NULLs, as fs
            # would. Unfortunately during resyncing, we'll have to consider regions
            # past the end of a file to be NULLs as well. This allows us to merge data
            # regions cleanly without rehacking the model.

            if len(old_data) < len(new_data):
                self._debug(
                    ("New data is past end of file by %d bytes. " "Padding with nulls.")
                    % (len(new_data) - len(old_data))
                )
                old_data += "\x00" * (len(new_data) - len(old_data))

        else:
            self._debug("We're a new file -- not adding a change record to log.")

        try:
            if self._manager.writeFile(self._path, offset, new_data, self._fdFlags, self._fdMode):
                if not self._isNewFile:
                    self._debug(
                        "Adding change to synclog [ %s | %d | %d | %s ]"
                        % (self._path, offset, offset + len(new_data), repr(old_data))
                    )

                    tsumufs.syncLog.addChange(self._path, offset, offset + len(new_data), old_data)

            self._debug("Wrote %d bytes to cache." % len(new_data))

            return len(new_data)

        except OSError, e:
            self._debug("OSError caught: errno %d: %s" % (e.errno, e.strerror))
            return -e.errno
Exemple #4
0
  def _cacheFile(self, fusepath):
    '''
    Cache the file referenced by path.

    This method locks the file for reading, determines what type it
    is, and attempts to cache it. Note that if there was an issue
    reading from the fsMount, this method will mark the fs mount as
    being unavailble.

    Note: The touch cache isn't implemented here at the moment. As a
    result, the entire cache is considered permacache for now.

    Note: fs error checking and disable are not handled here for the
    moment. Any errors that would ordinarily shut down the fs mount
    are just reported as normal OSErrors, aside from ENOENT.

    Returns:
      Nothing.

    Raises:
      OSError if there was an issue attempting to copy the file
      across to cache.
    '''

    # TODO(jtg): Add support for storing the UID/GID

    self.lockFile(fusepath)

    try:
      fspath = tsumufs.fsPathOf(fusepath)
      cachepath = tsumufs.cachePathOf(fusepath)

      document = tsumufs.fsOverlay[fusepath]

      if stat.S_ISDIR(document.mode):
        # Caching a directory to disk -- call cacheDir instead.
        self._debug('Request to cache a directory -- calling _cacheDir')
        self._cacheDir(fusepath)

      else:
        self._debug('Caching file %s to disk.' % fusepath)

        if (stat.S_ISREG(document.mode)  or
            stat.S_ISFIFO(document.mode) or
            stat.S_ISSOCK(document.mode) or
            stat.S_ISCHR(document.mode)  or
            stat.S_ISBLK(document.mode)):

          try:
              shutil.copyfileobj(tsumufs.fsMount.open(fusepath, os.O_RDONLY | os.O_BINARY),
                                 open(cachepath, "wb"))
          except AttributeError, e:
              shutil.copyfileobj(tsumufs.fsMount.open(fusepath, os.O_RDONLY),
                                 open(cachepath, "w"))

        elif stat.S_ISLNK(document.mode):
          dest = os.readlink(fspath)

          try:
            os.unlink(cachepath)
          except OSError, e:
            if e.errno != errno.ENOENT:
              raise

          os.symlink(dest, cachepath)