# # Copyright (C) 2006-2010 Nexedi SA # # This program 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 2 # of the License, or (at your option) any later version. # # This program 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 this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. from neo import util from neo.exception import DatabaseFailure class DatabaseManager(object): """This class only describes an interface for database managers.""" def __init__(self): """ Initialize the object. """ self._under_transaction = False def isUnderTransaction(self): return self._under_transaction def begin(self): """ Begin a transaction """ if self._under_transaction: raise DatabaseFailure('A transaction as already began') self._begin() self._under_transaction = True def commit(self): """ Commit the current transaction """ if not self._under_transaction: raise DatabaseFailure('The transaction as not began') self._commit() self._under_transaction = False def rollback(self): """ Rollback the current transaction """ self._rollback() self._under_transaction = False def setup(self, reset = 0): """Set up a database. If reset is true, existing data must be discarded.""" raise NotImplementedError def _begin(self): raise NotImplementedError def _commit(self): raise NotImplementedError def _rollback(self): raise NotImplementedError def getConfiguration(self, key): """ Return a configuration value, returns None if not found or not set """ raise NotImplementedError def setConfiguration(self, key, value): """ Set a configuration value """ if self._under_transaction: self._setConfiguration(key, value) else: self.begin() try: self._setConfiguration(key, value) except: self.rollback() raise self.commit() def _setConfiguration(self, key, value): raise NotImplementedError def getUUID(self): """ Load an UUID from a database. """ return util.bin(self.getConfiguration('uuid')) def setUUID(self, uuid): """ Store an UUID into a database. """ self.setConfiguration('uuid', util.dump(uuid)) def getNumPartitions(self): """ Load the number of partitions from a database. """ n = self.getConfiguration('partitions') if n is not None: return int(n) def setNumPartitions(self, num_partitions): """ Store the number of partitions into a database. """ self.setConfiguration('partitions', num_partitions) def getNumReplicas(self): """ Load the number of replicas from a database. """ n = self.getConfiguration('replicas') if n is not None: return int(n) def setNumReplicas(self, num_replicas): """ Store the number of replicas into a database. """ self.setConfiguration('replicas', num_replicas) def getName(self): """ Load a name from a database. """ return self.getConfiguration('name') def setName(self, name): """ Store a name into a database. """ self.setConfiguration('name', name) def getPTID(self): """ Load a Partition Table ID from a database. """ return util.bin(self.getConfiguration('ptid')) def setPTID(self, ptid): """ Store a Partition Table ID into a database. """ self.setConfiguration('ptid', util.dump(ptid)) def getLastOID(self): """ Returns the last OID used """ return util.bin(self.getConfiguration('loid')) def setLastOID(self, loid): """ Set the last OID used """ self.setConfiguration('loid', util.dump(loid)) def getPartitionTable(self): """Return a whole partition table as a tuple of rows. Each row is again a tuple of an offset (row ID), an UUID of a storage node, and a cell state.""" raise NotImplementedError def getLastTID(self, all = True): """Return the last TID in a database. If all is true, unfinished transactions must be taken account into. If there is no TID in the database, return None.""" raise NotImplementedError def getUnfinishedTIDList(self): """Return a list of unfinished transaction's IDs.""" raise NotImplementedError def objectPresent(self, oid, tid, all = True): """Return true iff an object specified by a given pair of an object ID and a transaction ID is present in a database. Otherwise, return false. If all is true, the object must be searched from unfinished transactions as well.""" raise NotImplementedError def getObject(self, oid, tid = None, before_tid = None): """Return a tuple of a serial, next serial, a compression specification, a checksum, and object data, if a given object ID is present. Otherwise, return None. If tid is None and before_tid is None, the latest revision is taken. If tid is specified, the given revision is taken. If tid is not specified, but before_tid is specified, the latest revision before the given revision is taken. The next serial is a serial right after before_tid, if specified. Otherwise, it is None.""" raise NotImplementedError def changePartitionTable(self, ptid, cell_list): """Change a part of a partition table. The list of cells is a tuple of tuples, each of which consists of an offset (row ID), an UUID of a storage node, and a cell state. The Partition Table ID must be stored as well.""" raise NotImplementedError def setPartitionTable(self, ptid, cell_list): """Set a whole partition table. The semantics is the same as changePartitionTable, except that existing data must be thrown away.""" raise NotImplementedError def dropPartition(self, offset): """ Drop objects and transactions assigned to a partition table, this should be called only during storage initialization, to clear existing data that could be stored by a previous cluster life """ raise NotImplementedError('this method must be overriden') def dropUnfinishedData(self): """Drop any unfinished data from a database.""" raise NotImplementedError def storeTransaction(self, tid, object_list, transaction, temporary = True): """Store a transaction temporarily, if temporary is true. Note that this transaction is not finished yet. The list of objects contains tuples, each of which consists of an object ID, a compression specification, a checksum and object data. The transaction is either None or a tuple of the list of OIDs, user information, a description, extension information and transaction pack state (True for packed).""" raise NotImplementedError def finishTransaction(self, tid): """Finish a transaction specified by a given ID, by moving temporarily data to a finished area.""" raise NotImplementedError def deleteTransaction(self, tid, all = False): """Delete a transaction specified by a given ID from a temporarily area. If all is true, it must be deleted even from a finished area.""" raise NotImplementedError def getTransaction(self, tid, all = False): """Return a tuple of the list of OIDs, user information, a description, and extension information, for a given transaction ID. If there is no such transaction ID in a database, return None. If all is true, the transaction must be searched from a temporary area as well.""" raise NotImplementedError def getOIDList(self, offset, length, num_partitions, partition_list): """Return a list of OIDs in descending order from an offset, at most the specified length. The list of partitions are passed to filter out non-applicable TIDs.""" raise NotImplementedError def getObjectHistory(self, oid, offset = 0, length = 1): """Return a list of serials and sizes for a given object ID. The length specifies the maximum size of such a list. The first serial must be the last serial, and the list must be sorted in descending order. If there is no such object ID in a database, return None.""" raise NotImplementedError def getTIDList(self, offset, length, num_partitions, partition_list): """Return a list of TIDs in descending order from an offset, at most the specified length. The list of partitions are passed to filter out non-applicable TIDs.""" raise NotImplementedError def getTIDListPresent(self, tid_list): """Return a list of TIDs which are present in a database among the given list.""" raise NotImplementedError def getSerialListPresent(self, oid, serial_list): """Return a list of serials which are present in a database among the given list.""" raise NotImplementedError