summaryrefslogblamecommitdiffstats
path: root/combox/silo.py
blob: 0f2de3c5dd0149fd8096f8c58ba7af826164810f (plain) (tree)
1
2
3

                       
                                               



















                                                                     
                          


                                 
 
                         
                                                     
 





                                                                  
 
       
 
                                     
                                 



                            

                                                                 
 
                                                            
                                                                         
                                                             










                                                                           





                                                   



                        


                                     

                                                         
 

                            
                                     
 

                                                                     
 



                                                        

           
                     


                                            

 
                   







                                                          

                                                                     
                     

                                    

 
                            
                                   
 






                                                                       

           
            
                         

                                         


                                              


                            
                                                  
 




                                                                       

           
                     




                                          

 
                                       










                                                                      
 
           


                                    
                     

                                            






                                  


                        

                                     



                              
                                             









                                                                                         
 

           
                     
                       


                                                 



                                                



                                                                     



                                             

                                                         





                                                                           
 





                                                                  
                                     











                                                                                                                                     
 
           






                                                        


                                     
                                                                                           
 





                                                                  
 
           







                                                         
# -*- coding: utf-8 -*-
#
#    Copyright (C) 2016 Dr. Robert C. Green II.
#
#    This file is part of Combox.
#
#   Combox is free software: you can redistribute it and/or modify it
#   under the terms of the GNU General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   Combox is distributed in the hope that it will be useful, but
#   WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#   General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with Combox (see COPYING).  If not, see
#   <http://www.gnu.org/licenses/>.

import pickledb

from os import path
from threading import Lock

from combox.file import hash_file


class ComboxSilo(object):
    """Helps keep track of files in combox directory.

    :param dict config:
        A dictionary that contains configuration information about
        combox.
    :param threading.Lock lock:
        Lock used by :class:`.ComboxDirMonitor` and
        :class:`.NodeDirMonitor` to access this object.

    """

    def __init__(self, config, lock):
        """Initialize ComboxSilo.

        """
        self.config = config

        self.silo_path = path.join(config['silo_dir'], 'silo.db')
        self.db = pickledb.load(self.silo_path, True)

        ## things we need for housekeep the node directories
        self.node_dicts = ['file_created', 'file_modified', 'file_moved',
                           'file_deleted', 'file_moved_info']
        """List of names of dictionaries stored in DB to housekeep the node
           directories.

        Initialized to::

            ['file_created', 'file_modified', 'file_moved',
             'file_deleted', 'file_moved_info']

        when :class:`ComboxSilo` object is created.

        """

        # created the dicts if not already created.
        for ndict in self.node_dicts:
            if not self.db.get(ndict):
                self.db.dcreate(ndict)

        self.lock = lock


    def reload(self):
        """Re-loads the DB from disk.

        """
        with self.lock:
            self.db = pickledb.load(self.silo_path, True)


    def update(self, filep):
        """Update filep's info in DB.

        Path of `filep` and the hash of its content is written to the
        DB.

        :param str filep:
            Path to the file under the combox directory.
        :returns: `True`
        :rtype: bool

        """
        self.reload()
        with self.lock:
            fhash = hash_file(filep)
            return self.db.set(filep, fhash)


    def keys(self):
        """Returns list of file' paths tracked by combox.

        :returns:
            List of file paths of files tracked by combox.
        :rtype:
            `True`

        """
        # this is why Redis or some other key-value DB should be used
        # instead of PickleDB
        self.reload()
        with self.lock:
            return self.db.db.keys()


    def remove(self, filep):
        """Removes `filep` from DB.

        :param str filep:
            Path to a file under combox directory whose information
            has to be removed from the DB.
        :returns:
            Returns `False` if `filep` is not present in the DB; `True`
            otherwise.
        :rtype: bool

        """
        try:
            self.reload()
            with self.lock:
                return self.db.rem(filep)
        except KeyError, e:
            # means `filep' not present in db.
            return False


    def exists(self, filep):
        """Checks if filep's info is stored in DB.

        :param str filep:
            Path to a file under the  combox directory.
        :returns:
            Returns `True` if filep's info is in DB; `False` otherwise.
        :rtype: bool

        """
        self.reload()
        with self.lock:
            if self.db.get(filep) is None:
                return False
            else:
                return True


    def stale(self, filep, fhash=None):
        """Checks if filep's info in the DB is outdated.

        :param str filep:
            Path to a file under the combox directory.
        :param bool fhash:
            If not `None`, it is assumed to be filep's hash.
        :returns:
            Returns `True`, if filep's hash is outdated; `False` if
            filep's hash is correct; `None` if filep's info is not yet
            stored in DB.
        :rtype: bool

        """
        if not fhash:
            fhash = hash_file(filep)

        self.reload()
        with self.lock:
            fhash_in_db = self.db.get(filep)

        if fhash_in_db is None:
            return None
        elif fhash == fhash_in_db:
            return False
        else:
            return True


    def nodedicts(self):
        """Returns :attr:`node_dicts`

        """
        return self.node_dicts


    def node_set(self, type_, file_, num=-1):
        """Update information about the shard of `file_` in dictionary `type_` in the DB.

        :param str type_:
            The name of the dictinary in DB. It must be one of the
            following values: `file_created`, `file_modified`,
            `file_moved`, `file_deleted`.
        :param str file_:
            Path of the file under the combox directory.
        :param int num:
            Integer associated with the `file_`.

        """

        self.reload()
        with self.lock:
            if num != -1:
                self.db.dadd(type_, (file_, num))
                return
            try:
                num = self.db.dget(type_, file_)
                num += 1
            except KeyError, e:
                # I don't think this is the right way to do this. :|
                #
                # If we are here it means file_ is not already there,
                # so:
                num = 1
            self.db.dadd(type_, (file_, num))


    def node_store_moved_info(self, src_path, dest_path):
        """
        Make note of a file/directory moved from `src_path` to `dest_path`.

        :param str src_path:
            The source path of the file being moved.
        :param str dest_path:
            The destination path of the file being moved.

        """
        self.reload()
        with self.lock:
            self.db.dadd('file_moved_info', (src_path, dest_path))


    def node_get(self, type_, file_):
        """Returns a number denoting the number of node directories in which the `file_`'s shards was created/modified/moved/deleted.

        :param str type_:
            The name of the dictinary in DB. It must be one of the
            following values: `file_created`, `file_modified`,
            `file_moved`, `file_deleted`.
        :param str file_:
            Path of the file under the combox directory.
        :returns:
            Number denoting the number of node directories in which
            the `file_`' shards were created/modified/moved/deleted.
        :rtype: int

        """
        self.reload()
        with self.lock:
            try:
                return self.db.dget(type_, file_)
            except KeyError, e:
                # file_ info not there under type_ dict.
                return None


    def node_rem(self, type_, file_):
        """Removes information about the shards of `file_` in the `type_` dictionary in DB.

        :param str type_:
            The name of the dictinary in DB. It must be one of the
            following values: `file_created`, `file_modified`,
            `file_moved`, `file_deleted`.
        :param str file_:
            Path of the file under the combox directory.

        """
        self.reload()
        with self.lock:
            try:
                return self.db.dpop(type_, file_)
            except KeyError, e:
                # means file_'s info was already removed.
                # do nothing
                pass