Ejemplo n.º 1
0
    def add(self, data):
        """Add a new element to the queue and return its name.
        Arguments:

            data - element as a dictionary (should conform to the schema)

        Raise:

            QueueError - problem with schema definition or data
            OSError    - problem putting element on disk

        Note:

          the destination directory must _not_ be created beforehand as
          it would be seen as a valid (but empty) element directory by
          another process, we therefore use rename() from a temporary
          directory
        """
        if not self.type:
            raise QueueError("unknown schema")
        while True:
            temp = "%s/%s/%s" % (self.path, TEMPORARY_DIRECTORY, _name(self.rndhex))
            if _special_mkdir(temp, self.umask):
                break
        for name in data.keys():
            if name not in self.type:
                raise QueueError("unexpected data: %s" % name)
            if self.type[name] == "binary":
                if type(data[name]) not in VALID_STR_TYPES:
                    raise QueueError("unexpected binary data in %s: %r" % (name, data[name]))
                _file_write("%s/%s" % (temp, name), 0, self.umask, data[name])
            elif self.type[name] == "string":
                if type(data[name]) not in VALID_STR_TYPES:
                    raise QueueError("unexpected string data in %s: %r" % (name, data[name]))
                _file_write("%s/%s" % (temp, name), 1, self.umask, data[name])
            elif self.type[name] == "table":
                if not isinstance(data[name], dict):
                    raise QueueError("unexpected table data in %s: %r" % (name, data[name]))
                _file_write("%s/%s" % (temp, name), 1, self.umask, _hash2string(data[name]))
            else:
                raise QueueError("unexpected data type in %s: %r" % (name, self.type[name]))
        for name in self.mandatory.keys():
            if name not in data:
                raise QueueError("missing mandatory data: %s" % name)
        while True:
            name = "%s/%s" % (self._insertion_directory(), _name(self.rndhex))
            path = "%s/%s" % (self.path, name)
            try:
                os.rename(temp, path)
                return name
            except Exception:
                error = sys.exc_info()[1]
                if error.errno != errno.ENOTEMPTY and error.errno != errno.EEXIST:
                    raise OSError("cannot rename(%s, %s): %s" % (temp, path, error))
Ejemplo n.º 2
0
    def _add_data(self, data):
        """Write 'data' to a file.

        Return: (tuple) directory name where the file was written, full path to
        the temporary file.
        """
        _dir = self._add_dir()
        while 1:
            tmp = '%s/%s/%s%s' % (self.path, _dir, _name(self.rndhex),
                                  TEMPORARY_SUFFIX)
            try:
                if is_bytes(data):
                    new_file = _file_create(tmp, umask=self.umask, utf8=False)
                else:
                    new_file = _file_create(tmp, umask=self.umask, utf8=True)
            except EnvironmentError:
                error = sys.exc_info()[1]
                if error.errno == errno.ENOENT:
                    _special_mkdir('%s/%s' % (self.path, _dir), self.umask)
                    continue
            else:
                if new_file:
                    break
        new_file.write(data)
        new_file.close()
        return _dir, tmp
Ejemplo n.º 3
0
    def remove(self, ename):
        """Remove locked element from the queue.

        Arguments:
            ename - name of an element

        Raise:
            QueueError - invalid element name; element not locked;
                         unexpected file in the element directory

            OSError    - can't rename/remove a file/directory

        Note:
            doesn't return anything explicitly (i.e. returns NoneType)
            or fails
        """
        _check_element(ename)
        if not self._is_locked(ename):
            raise QueueError("cannot remove %s: not locked" % ename)
        # move the element out of its intermediate directory
        path = "%s/%s" % (self.path, ename)
        while True:
            temp = "%s/%s/%s" % (self.path, OBSOLETE_DIRECTORY, _name(self.rndhex))
            try:
                os.rename(path, temp)
                break
            except Exception:
                error = sys.exc_info()[1]
                if error.errno != errno.ENOTEMPTY and error.errno != errno.EEXIST:
                    raise OSError("cannot rename(%s, %s): %s" % (ename, temp, error))
                    # RACE: the target directory was already present...
        # remove the data files
        for name in _directory_contents(temp):
            if name == LOCKED_DIRECTORY:
                continue
            if not _FILE_REGEXP.match(name):
                raise QueueError("unexpected file in %s: %s" % (temp, name))
            path = "%s/%s" % (temp, name)
            try:
                os.unlink(path)
            except Exception:
                error = sys.exc_info()[1]
                raise OSError("cannot unlink(%s): %s" % (path, error))
        # remove the locked directory
        path = "%s/%s" % (temp, LOCKED_DIRECTORY)
        while True:
            try:
                os.rmdir(path)
            except Exception:
                error = sys.exc_info()[1]
                raise OSError("cannot rmdir(%s): %s" % (path, error))
            try:
                os.rmdir(temp)
                return
            except Exception:
                error = sys.exc_info()[1]
                if error.errno != errno.ENOTEMPTY and error.errno != errno.EEXIST:
                    raise OSError("cannot rmdir(%s): %s" % (temp, error))
Ejemplo n.º 4
0
    def _add_path(self, tmp, _dir):
        """Given temporary file and directory where it resides: create a hard
        link to that file and remove initial one.

        Return: element name (<directory name>/<file name>).
        """
        while 1:
            name = _name(self.rndhex)
            new = '%s/%s/%s' % (self.path, _dir, name)
            try:
                os.link(tmp, new)
            except OSError:
                error = sys.exc_info()[1]
                if error.errno != errno.EEXIST:
                    raise error
                else:
                    continue
            os.unlink(tmp)
            return '%s/%s' % (_dir, name)
Ejemplo n.º 5
0
    def add(self, data):
        """Add a new element to the queue and return its name.
        Arguments:

            data - element as a dictionary (should conform to the schema)

        Raise:

            QueueError - problem with schema definition or data
            OSError    - problem putting element on disk

        Note:

          the destination directory must _not_ be created beforehand as
          it would be seen as a valid (but empty) element directory by
          another process, we therefore use rename() from a temporary
          directory
        """
        if not self.type:
            raise QueueError("unknown schema")
        while True:
            temp = '%s/%s/%s' % (self.path, TEMPORARY_DIRECTORY,
                                 _name(self.rndhex))
            if _special_mkdir(temp, self.umask):
                break
        for name in data.keys():
            if name not in self.type:
                raise QueueError("unexpected data: %s" % name)
            if self.type[name] == 'binary':
                if type(data[name]) not in VALID_STR_TYPES:
                    raise QueueError("unexpected binary data in %s: %r" %
                                     (name, data[name]))
                _file_write('%s/%s' % (temp, name), 0, self.umask, data[name])
            elif self.type[name] == 'string':
                if type(data[name]) not in VALID_STR_TYPES:
                    raise QueueError("unexpected string data in %s: %r" %
                                     (name, data[name]))
                _file_write('%s/%s' % (temp, name), 1, self.umask, data[name])
            elif self.type[name] == 'table':
                if not isinstance(data[name], dict):
                    raise QueueError("unexpected table data in %s: %r" %
                                     (name, data[name]))
                _file_write('%s/%s' % (temp, name), 1, self.umask,
                            _hash2string(data[name]))
            else:
                raise QueueError("unexpected data type in %s: %r" %
                                 (name, self.type[name]))
        for name in self.mandatory.keys():
            if name not in data:
                raise QueueError("missing mandatory data: %s" % name)
        while True:
            name = '%s/%s' % (self._insertion_directory(), _name(self.rndhex))
            path = '%s/%s' % (self.path, name)
            try:
                os.rename(temp, path)
                return name
            except Exception:
                error = sys.exc_info()[1]
                if error.errno != errno.ENOTEMPTY and \
                        error.errno != errno.EEXIST:
                    raise OSError("cannot rename(%s, %s): %s" %
                                  (temp, path, error))
Ejemplo n.º 6
0
    def remove(self, ename):
        """Remove locked element from the queue.

        Arguments:
            ename - name of an element

        Raise:
            QueueError - invalid element name; element not locked;
                         unexpected file in the element directory

            OSError    - can't rename/remove a file/directory

        Note:
            doesn't return anything explicitly (i.e. returns NoneType)
            or fails
        """
        _check_element(ename)
        if not self._is_locked(ename):
            raise QueueError("cannot remove %s: not locked" % ename)
        # move the element out of its intermediate directory
        path = '%s/%s' % (self.path, ename)
        while True:
            temp = '%s/%s/%s' % (self.path, OBSOLETE_DIRECTORY,
                                 _name(self.rndhex))
            try:
                os.rename(path, temp)
                break
            except Exception:
                error = sys.exc_info()[1]
                if error.errno != errno.ENOTEMPTY and \
                        error.errno != errno.EEXIST:
                    raise OSError("cannot rename(%s, %s): %s" %
                                  (ename, temp, error))
                    # RACE: the target directory was already present...
        # remove the data files
        for name in _directory_contents(temp):
            if name == LOCKED_DIRECTORY:
                continue
            if not _FileRegexp.match(name):
                raise QueueError("unexpected file in %s: %s" % (temp, name))
            path = '%s/%s' % (temp, name)
            try:
                os.unlink(path)
            except Exception:
                error = sys.exc_info()[1]
                raise OSError("cannot unlink(%s): %s" % (path, error))
        # remove the locked directory
        path = '%s/%s' % (temp, LOCKED_DIRECTORY)
        while True:
            try:
                os.rmdir(path)
            except Exception:
                error = sys.exc_info()[1]
                raise OSError("cannot rmdir(%s): %s" % (path, error))
            try:
                os.rmdir(temp)
                return
            except Exception:
                error = sys.exc_info()[1]
                if error.errno != errno.ENOTEMPTY and \
                        error.errno != errno.EEXIST:
                    raise OSError("cannot rmdir(%s): %s" % (temp, error))