X-Git-Url: https://git.teslayout.com/public/public/public/?a=blobdiff_plain;f=source%2Fdbos%2FStorageArea.cpp;fp=source%2Fdbos%2FStorageArea.cpp;h=0000000000000000000000000000000000000000;hb=851ff2962362fd5bad874e8ed91445b296eaca24;hp=830f64777845bac0a646ee627c3c2189bdb63f2b;hpb=78be86969d2f26a9084b0c4af6ce43d5fa4ed3fd;p=anna.git diff --git a/source/dbos/StorageArea.cpp b/source/dbos/StorageArea.cpp deleted file mode 100644 index 830f647..0000000 --- a/source/dbos/StorageArea.cpp +++ /dev/null @@ -1,1081 +0,0 @@ -// ANNA - Anna is Not Nothingness Anymore // -// // -// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo // -// // -// See project site at http://redmine.teslayout.com/projects/anna-suite // -// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE // - - -#include - -#include - -#include -#include - -#include -#include - -#include -#include - -using namespace std; -using namespace anna; - -StorageArea::StorageArea(const char* name, const Size maxSize, ObjectAllocator objectAllocator, const StorageArea::AccessMode::_v accessMode, const int errorCode) : - a_name(name), - a_maxSize(maxSize), - a_objectAllocator(objectAllocator), - a_accessMode(accessMode), - a_errorCode(errorCode), - a_indexBlock(0), - a_sizeof(0), - a_doneReuse(0) { - a_blocks.push_back(a_currentBlock = new Block(objectAllocator, maxSize)); - a_hit = a_fault = 0; -} - -StorageArea::~StorageArea() { -} - -//------------------------------------------------------------------------------------------------ -// Carga los datos del objeto y los guarda en el area de almacemiento. -// -// (1) Si no esta en memoria => se carga. -// (1.1) Si el registro no existe => se progresa la posible excepcion. -// -// (2) Cambia la politica de refresco de las areas de almacenamiento ReadWrite/Dirty. La carga solo se -// realizara cuando la copia de utilizacion sea 0. Ademas de la mejora de rendimiento aseguramos que -// la estabilidad de una instancia se mantiene durante toda la vida de esta. Por ejmplo evitamos que -// una instancia A este trabajando con una copia de una instancia que estamos liberando y volviendo -// a cargar con datos totalmente distintos ... imaginad que estamos recorriendo un vector asociado -// o algo asi. -// -// (3) Si no ha podido ser recargada (seguramente tiene mas de una referencia) debe evitar el -// uso en caso de que este marcada como Dirty. -// (4) Si el contador de uso es cero => que ya esta marcado como memoria libre, pero recordar que -// tambien puede estar en la memoria activa (pendiente de liberar y/o volver a usar). En este -// caso se ha reusado. -//------------------------------------------------------------------------------------------------ -Object* StorageArea::instance(Connection* connection, Loader& loader) -throw(RuntimeException, DatabaseException) { - const Index index = loader.getIndex(); - Object* result(NULL); - Instance* instance(NULL); - LOGDEBUG( - string msg("Instantiate (init) | "); - msg += asString(); - msg += " | "; - msg += loader.asString(); - msg += " | Index: "; - msg += functions::asHexString(index); - Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION) - ); - loader.a_connection = connection; - std::string name("dbos::StorageArea::instance with "); - name += typeid(loader).name(); - Guard guard(this, name.c_str()); - iterator ii = a_directory.find(index); - - if(ii == a_directory.end()) { // (1) - a_fault ++; - - if(loader.load(connection, this) == true) { // (1.1) - pair rr; - bool wasInserted = false; - instance = allocate(); - - try { - instance->object->setIndex(index); - /* Al añadir la instancia antes de invocar al método Object::initialize - * nos aseguramos de que se permitan implementar relaciones circulares - */ - rr = a_directory.insert(value_type(index, instance)); - wasInserted = true; - result = instance->object; - instance->flags |= Flag::InProgress; - instance->object->initialize(loader); - instance->object->a_isStored = true; - instance->flags &= Flag::Done; - } catch(DatabaseException&) { - instance->flags &= Flag::Done; - - if(wasInserted) - a_directory.erase(rr.first); - - a_holes.insert(instance, Holes::Mode::ReadyToReuse); - throw; - } catch(RuntimeException&) { - instance->flags &= Flag::Done; - - if(wasInserted) - a_directory.erase(rr.first); - - a_holes.insert(instance, Holes::Mode::ReadyToReuse); - throw; - } - } - } else { - static const bool IgnoreDirty = true; - verifyStatus(instance = StorageArea::instance(ii), IgnoreDirty); - - switch(a_accessMode) { - case AccessMode::ReadOnly: - result = ((instance->flags & Flag::Dirty) == 0) ? instance->object : reload(connection, loader, instance); - break; - case AccessMode::ReadWrite: - result = (instance->copyCounter > 0) ? instance->object : reload(connection, loader, instance); - break; - case AccessMode::ReadEver: - result = reload(connection, loader, instance); - break; - } - - if(instance->flags & Flag::Dirty) { // (3) - string msg(asString()); - msg += " | "; - msg += asString(instance); - msg += " | Instance selected as unusable"; - throw RuntimeException(msg, ANNA_FILE_LOCATION); - } - - if(result != NULL) { - a_holes.erase(instance); // (4) - instance->copyCounter ++; - a_hit ++; - } - } - - LOGINFORMATION( - string msg("Instantiate (final) | "); - msg += asString(); - msg += " | "; - msg += asString(instance); - Logger::information(msg, ANNA_FILE_LOCATION) - ); - return result; -} - -Object* StorageArea::instance(Connection* connection, CrossedLoader& crossedLoader, Loader& loader) -throw(RuntimeException, DatabaseException) { - Object* result = NULL; - crossedLoader.a_connection = connection; - // Si el seek devuelve 'true' es que ya tiene cargada la correspondencia entre la clave alternativa y la - // clave principal usada en el Loader recibido como parámetro. - bool loaded = (crossedLoader.seek() == false) ? crossedLoader.load(connection, this) : true; - - if(loaded == true) { - /* - * Transfiere la clave principal conseguida por el cargador cruzado. - */ - loader.upload(crossedLoader); - result = instance(connection, loader); - /* - * Da la posibilidad de que el cargador cruzado mantenga la correspondencia entre sus claves y las claves primarias - */ - crossedLoader.download(loader); - } - - return result; -} - -//------------------------------------------------------------------------- -// Crea un nuevo objeto en el area de almacenamiento. -//------------------------------------------------------------------------- -Object* StorageArea::create(Connection* connection, Creator& creator) -throw(RuntimeException, DatabaseException) { - const Index index = creator.getIndex(); - Instance* instance = NULL; - Object* result = NULL; - - if(a_accessMode == AccessMode::ReadOnly) { - string msg(asString()); - msg += " | Cannot create object with AccessMode::ReadOnly"; - throw RuntimeException(msg, ANNA_FILE_LOCATION); - } - - LOGDEBUG( - string msg(asString()); - msg += " | "; - msg += creator.asString(); - msg += " | Index: "; - msg += functions::asHexString(index); - Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION) - ); - creator.a_connection = connection; - std::string name("dbos::StorageArea::create with "); - name += typeid(creator).name(); - Guard guard(this, name.c_str()); - iterator ii = a_directory.find(index); - - if(ii == a_directory.end()) { - pair rr; - bool wasInserted = false; - a_fault ++; - instance = allocate(); - - try { - instance->object->setIndex(index); - instance->copyCounter = 1; - result = instance->object; - rr = a_directory.insert(value_type(index, instance)); - wasInserted = true; - instance->flags |= Flag::InProgress; - instance->object->create(creator); - instance->flags &= Flag::Done; - instance->object->a_isStored = false; - } catch(DatabaseException&) { - instance->flags &= Flag::Done; - - if(wasInserted) - a_directory.erase(rr.first); - - a_holes.insert(instance, Holes::Mode::ReadyToReuse); - throw; - } catch(RuntimeException&) { - instance->flags &= Flag::Done; - - if(wasInserted) - a_directory.erase(rr.first); - - a_holes.insert(instance, Holes::Mode::ReadyToReuse); - throw; - } - } else { - verifyStatus(instance = StorageArea::instance(ii)); - a_hit ++; - a_holes.erase(instance); - instance->copyCounter ++; - result = instance->object; - } - - LOGINFORMATION( - string msg("Create | "); - msg += asString(); - msg += " | "; - msg += asString(instance); - Logger::information(msg, ANNA_FILE_LOCATION) - ); - return result; -} - -//------------------------------------------------------------------------- -// Carga los datos del objeto y los guarda en el area de almacemiento. -// -// (1) Si tiene cuenta 0 => estaba en la lista de objetos liberados => -// lo sacamos de ah� -//------------------------------------------------------------------------- -Object* StorageArea::find(Loader& loader) -throw(RuntimeException) { - const Index index = loader.getIndex(); - Instance* instance = NULL; - Object* result = NULL; - LOGDEBUG( - string msg(asString()); - msg += " | "; - msg += loader.asString(); - msg += " | Index: "; - msg += functions::asHexString(index); - Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION) - ); - std::string name("dbos::StorageArea::find with "); - name += typeid(loader).name(); - Guard guard(this, name.c_str()); - iterator ii = a_directory.find(index); - - if(ii != a_directory.end()) { - verifyStatus(instance = StorageArea::instance(ii)); - a_hit ++; - a_holes.erase(instance); - instance->copyCounter ++; - result = instance->object; - } else - a_fault ++; - - LOGDEBUG( - string msg("Find | "); - msg += asString(); - msg += " | "; - msg += asString(instance); - Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION) - ); - return result; -} - -Object* StorageArea::duplicate(const Object* object) -throw(RuntimeException) { - if(object == NULL) return NULL; - - std::string name("dbos::StorageArea::duplicate with "); - name += typeid(*object).name(); - Guard guard(this, name.c_str()); - iterator ii = a_directory.find(object->getIndex()); - - if(ii == a_directory.end()) { - a_fault ++; - string msg(asString()); - msg += " | Index: "; - msg += functions::asHexString(object->getIndex()); - msg += " | Invalid instance"; - throw RuntimeException(msg, ANNA_FILE_LOCATION); - } - - Instance* instance = NULL; - verifyStatus(instance = StorageArea::instance(ii)); - a_holes.erase(instance); - instance->copyCounter ++; - a_hit ++; - LOGINFORMATION( - string msg("Duplicate | "); - msg += asString(); - msg += " | "; - msg += asString(instance); - Logger::information(msg, ANNA_FILE_LOCATION) - ); - return instance->object; -} - -bool StorageArea::isLoaded(const Loader& loader) -throw(RuntimeException) { - const Index index = loader.getIndex(); - std::string name("dbos::StorageArea::isLoaded with "); - name += typeid(loader).name(); - Guard guard(this, name.c_str()); - iterator ii = a_directory.find(index); - const bool result = (ii != a_directory.end()); - LOGDEBUG( - string msg(asString()); - msg += " | "; - msg += loader.asString(); - msg += " | Index: "; - msg += functions::asHexString((int) index); - msg += functions::asText(" | isLoaded: ", result); - Logger::debug(msg, ANNA_FILE_LOCATION); - ); - return result; -} - -void StorageArea::apply(Connection& connection, Recorder& recorder) -throw(RuntimeException, DatabaseException) { - ResultCode resultCode = connection.execute(recorder.getStatement()); - - if(resultCode.successful() == false) - throw DatabaseException(resultCode, ANNA_FILE_LOCATION); -} - -//------------------------------------------------------------------------------------------------ -// Borra un objeto del medio fisico => lo borra tambien de la cache -// -// (1) Como copyCounter = 0 => Lo metera en lista de huecos, le quitara del directorio y -// si fuera necesario invocara al 'destroy'. -// (2) No la puede sacar de la memoria porque tiene referencias activas, pero por lo menos la -// marca como no usable para intentar provocar los avisos de uso incorrecto y expulsar la -// instancia en cuanto pueda. -//------------------------------------------------------------------------------------------------ -void StorageArea::apply(Connection& connection, Eraser& eraser) -throw(RuntimeException, DatabaseException) { - if(a_accessMode == AccessMode::ReadOnly) { - string msg(asString()); - msg += " | Cannot erase object with AccessMode::ReadOnly"; - throw RuntimeException(msg, ANNA_FILE_LOCATION); - } - - Object* object = eraser.getObject(); - eraser.a_connection = &connection; - std::string name("dbos::StorageArea::apply with "); - name += typeid(eraser).name(); - Guard guard(this, name.c_str()); - Instance* instance = NULL; - - if(object != NULL) { - iterator ii = a_directory.find(object->getIndex()); - - if(ii != a_directory.end()) { - instance = StorageArea::instance(ii); - - if(instance->copyCounter > 1) { - instance->flags |= Flag::Incoherent; // (2) - string msg(eraser.asString()); - msg += " | Instances: "; - msg += functions::asString(instance->copyCounter); - msg += " | Cannot delete object"; - throw RuntimeException(msg, ANNA_FILE_LOCATION); - } - } - } - - ResultCode resultCode = connection.execute(eraser.getStatement()); - - if(resultCode.successful() == false) - throw DatabaseException(resultCode, ANNA_FILE_LOCATION); - - if(instance != NULL) { - instance->copyCounter = 0; - quickReusing(instance); // (1) - } -} - -//------------------------------------------------------------------------------------------------ -// Decrementa la cuenta de utilizacin del objeto recibido como parametro. -// -// (1) Si la instancia que estamos liberando esta marcada como 'Incoherente' y es la ultima -// referencia => es el momento de expulsarla de la memoria. -// (2) Queda a la espera de que se vuelva a usar la referencia o que el numero de registros en -// memoria alcance un numero tal que implique comenzar a reusar objetos liberados. -//------------------------------------------------------------------------------------------------ -void StorageArea::release(Object** object) -throw(RuntimeException) { - if(object == NULL) return; - - if(*object == NULL) return; - - std::string name("dbos::StorageArea::release with "); - name += typeid(**object).name(); - Guard guard(this, name.c_str()); - iterator ii = a_directory.find((*object)->getIndex()); - - if(ii == a_directory.end()) - return; - - Instance* instance = StorageArea::instance(ii); - - if(instance->copyCounter > 0) { - if(-- instance->copyCounter == 0) { - if(instance->flags & Flag::Incoherent) // (1) - quickReusing(instance); - else - a_holes.insert(instance, Holes::Mode::TimeWait); // (2) - } - } - - LOGINFORMATION( - string msg("Release | "); - msg += asString(); - msg += " | "; - msg += asString(instance); - Logger::information(msg, ANNA_FILE_LOCATION) - ); - *object = NULL; -} - -//------------------------------------------------------------------------------------------------ -// Elimina toda la informacin referente al objeto recibido como parametro. -// -// (1) No la puede sacar de la memoria porque tiene referencias activas, pero por lo menos la -// marca como no usable para intentar provocar los avisos de uso incorrecto y expulsar la -// instancia en cuanto pueda. -// (2) Como copyCounter = 0 => Lo metera en lista de huecos, le quitara del directorio y -// si fuera necesario invocara al 'destroy'. -//------------------------------------------------------------------------------------------------ -void StorageArea::erase(Object** object) -throw(RuntimeException) { - if(object == NULL) return; - - if(*object == NULL) return; - - std::string name("dbos::StorageArea::erase with "); - name += typeid(**object).name(); - Guard guard(this, name.c_str()); - iterator ii = a_directory.find((*object)->getIndex()); - - if(ii == a_directory.end()) - return; - - Instance* instance = StorageArea::instance(ii); - - if(instance->copyCounter > 1) { - instance->flags |= Flag::Incoherent; // (1) - string msg(asString()); - msg += " | "; - msg += asString(instance); - msg += " | Cannot dump instance"; - throw RuntimeException(msg, ANNA_FILE_LOCATION); - } - - LOGDEBUG( - string msg("Erase | "); - msg += asString(); - msg += " | "; - msg += asString(instance); - Logger::debug(msg, ANNA_FILE_LOCATION) - ); - instance->copyCounter = 0; - quickReusing(instance); // (2) - *object = NULL; -} - -void StorageArea::dirty(Object* object) -throw(RuntimeException) { - if(object == NULL) return; - - std::string name("dbos::StorageArea::dirty with "); - name += typeid(*object).name(); - Guard guard(this, name.c_str()); - iterator ii = a_directory.find(object->getIndex()); - - if(ii == a_directory.end()) - return; - - Instance* instance = StorageArea::instance(ii); - - if(instance->copyCounter > 1 && Logger::isActive(Logger::Warning)) { - string msg(asString()); - msg += " | "; - msg += asString(instance); - msg += " | More than one copy on instance to be selected"; - Logger::warning(msg, ANNA_FILE_LOCATION); - } - - LOGDEBUG( - string msg("Dirty | "); - msg += asString(); - msg += " | "; - msg += asString(instance); - Logger::debug(msg, ANNA_FILE_LOCATION) - ); -} - -//-------------------------------------------------------------------------------------------- -// Descarga todos los objetos de este area de almacenamiento. -// -// (1) Para que permite incluirla en los huecos. -// (3) Si fuera necesario invoca al destroy => cuando se reuse no tendra que hacerlo. -// (4) Si la entrada estaba marcada como 'incoherente' la desmarca, ya que hemos conseguido -// expulsarla de cache. -//-------------------------------------------------------------------------------------------- -void StorageArea::clear() -throw(RuntimeException) { - Guard guard(this, "dbos::StorageArea::clear"); - Instance* instance; - int n = 0; - - for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++) { - instance = StorageArea::instance(ii); - instance->copyCounter = 0; // (1) - a_holes.insert(instance, Holes::Mode::ReadyToReuse); - - if((instance->flags & Flag::Empty) == 0) { // (3) - LOGINFORMATION( - string msg("Destroy (clear) | "); - msg += asString(); - msg += " | "; - msg += asString(instance); - Logger::information(msg, ANNA_FILE_LOCATION); - ); - instance->object->destroy(); - instance->flags |= Flag::Empty; - } - - instance->flags &= Flag::NoIncoherent; // (4) - n ++; - } - - a_directory.clear(); - LOGWARNING( - string msg("Clear | "); - msg += asString(); - msg += functions::asText(" | Destroyed objects: ", n); - Logger::warning(msg, ANNA_FILE_LOCATION) - ); -} - -//--------------------------------------------------------------------------------------------------- -// Intenta recargar la informacion del medio fisico en la instancia del objeto. -// Si hay algun problema y la instancia no puede guardarse en la de objetos disponibles -// (a_holes.insert == false) => se marca como corrupto y no se podra usar hasta que -// que no se libere su ultima instancia. -// -// (1) Si hubiera algun problema al invocar al 'initialize' no habria que volver a invocar -// a este metodo. -// (2) Recordar que la recarga solo se intenta cuando la copyCounter = 0, por tanto en el caso de -// intentar recargar un registro que ha sido borrado no se vuelve a grabar como Ready porque -// YA esta en la lista de huecos y seria necesario borrarlo de esta, cambiarle el msHoleTime y -// volverlo a grabar, pero la cosa funciona porque se saca del directorio de objetos cargados -// y se libera su memoria. -//--------------------------------------------------------------------------------------------------- -Object* StorageArea::reload(dbms::Connection* connection, Loader& loader, StorageArea::Instance* instance) -throw(RuntimeException, dbms::DatabaseException) { - const bool enableUpdate = (instance->flags & Flag::Dirty) ? true : instance->object->enableUpdate(); - bool hasChanges(false); - - if(enableUpdate == true) { - try { - if(loader.load(connection, this) == false) { - checkIncoherence(instance); // (2) - return NULL; - } - } catch(RuntimeException&) { - checkIncoherence(instance); - throw; - } catch(dbms::DatabaseException&) { - checkIncoherence(instance); - throw; - } - - hasChanges = (instance->flags & Flag::Dirty) ? true : instance->object->hasChanges(loader); - } - - LOGDEBUG( - string msg("Reload | "); - msg += asString(); - msg += " | "; - msg += asString(instance); - msg += anna::functions::asText(" | EnableUpdate: ", enableUpdate); - msg += anna::functions::asText(" | HasChanges: ", hasChanges); - Logger::debug(msg, ANNA_FILE_LOCATION); - ); - - if(hasChanges == true) { - LOGINFORMATION( - string msg("Destroy (reload) | "); - msg += asString(); - msg += " | "; - msg += asString(instance); - Logger::information(msg, ANNA_FILE_LOCATION); - ); - instance->object->destroy(); - instance->flags |= Flag::Empty; // (1) - instance->object->initialize(loader); - instance->flags &= Flag::NoEmpty; - instance->flags &= Flag::NoDirty; - } - - return instance->object; -} - -//------------------------------------------------------------------------------------------------ -// Cuando intenta recargar la informacion de una instancia desde el medio fisico, pero el -// registro ha sido borrado => -// 1.- Si hay alguna instancia en uso => no puede liberar la instancia porque algun otro -// objeto la tiene referenciada => la marca como corrupta. -// 2.- Si hay una unica instancia en uso => puede liberarla -// -// (1) si la puede grabar en los huecos o la instancia ya esta en los huecos => saca el objeto -// del directorio porque yo no es valido. Recupera la coherencia memoria-medio_fisico -// porque ha conseguido "expulsar" de la cache el registro borrado. -// (2) No puede "expulsar" el registro de la cache porque hay algun otro objeto que lo esta -// referenciando => Marca ESTA instancia como incoherente => no se podra duplicar y volver -// a instanciar, etc, etc -//------------------------------------------------------------------------------------------------ -void StorageArea::checkIncoherence(StorageArea::Instance* instance) -throw() { - if(quickReusing(instance) == true) { - LOGWARNING( - string msg("dbos::StorageArea::checkIncoherence | "); - msg += asString(); - msg += " | "; - msg += asString(instance); - msg += " | Recover coherence between physical media and memory"; - Logger::warning(msg, ANNA_FILE_LOCATION); - ); - } else { // (2) - instance->flags |= Flag::Incoherent; - LOGWARNING( - string msg("dbos::StorageArea::checkIncoherence | "); - msg += asString(); - msg += " | "; - msg += asString(instance); - msg += " | Detected incoherence between physical media and memory"; - Logger::warning(msg, ANNA_FILE_LOCATION); - ); - } -} - -//------------------------------------------------------------------------------------------------ -// (1) si la puede grabar en los huecos o la instancia ya esta en los huecos => (2) -// (2) saca el objeto del directorio porque yo no es valido. -// (3) Si fuera necesario invoca al destroy => cuando se reuse no tendra que hacerlo. -// (4) Si la entrada estaba marcada como 'incoherente' la desmarca, ya que hemos conseguido -// expulsarla de cache. -// -// Recordar que en el caso de intentar recargar un registro que ha sido borrado no se vuelve -// a grabar como Ready porque ya esta en la lista de huecos y seria necesario borrarlo de -// esta, cambiarle el msHoleTime y volverlo a grabar. -//------------------------------------------------------------------------------------------------ -bool StorageArea::quickReusing(StorageArea::Instance* instance) -throw() { - bool result(false); - - if(a_holes.insert(instance, Holes::Mode::ReadyToReuse) == true) { // (1) - iterator ii = a_directory.find(instance->object->getIndex()); - - if(ii != a_directory.end()) // (2) - a_directory.erase(ii); - - if((instance->flags & Flag::Empty) == 0) { // (3) - LOGINFORMATION( - string msg("Destroy (quickreusing) | "); - msg += asString(); - msg += " | "; - msg += asString(instance); - Logger::information(msg, ANNA_FILE_LOCATION); - ); - instance->object->destroy(); - instance->flags |= Flag::Empty; - } - - instance->flags &= Flag::NoIncoherent; // (4) - result = true; - } - - return result; -} - -void StorageArea::verifyStatus(StorageArea::Instance* instance, const bool ignoreDirty) -throw(RuntimeException) { - if(instance->flags & Flag::Incoherent) { - string msg(asString()); - msg += " | "; - msg += asString(instance); - msg += " | Physical media and memory do not match"; - throw RuntimeException(msg, ANNA_FILE_LOCATION); - } - - if(instance->flags & Flag::Empty) { - string msg(asString()); - msg += " | "; - msg += asString(instance); - msg += " | Instance is empty"; - throw RuntimeException(msg, ANNA_FILE_LOCATION); - } - - if(ignoreDirty == false && (instance->flags & Flag::Dirty)) { - string msg(asString()); - msg += " | "; - msg += asString(instance); - msg += " | Instance is temporary locked"; - throw RuntimeException(msg, ANNA_FILE_LOCATION); - } - - if(instance->flags & Flag::InProgress) { - string msg(asString()); - msg += " | "; - msg += asString(instance); - msg += " | Instance already has word in progress"; - throw RuntimeException(msg, ANNA_FILE_LOCATION); - } -} - -string StorageArea::asString() const -throw() { - string result("dbos::StorageArea { Name: "); - const int ratio = (a_hit == 0) ? 0 : (a_hit * 100) / (a_fault + a_hit); - /* Nº real de objetos en uso. En el directorio también se mantienen los que tienen la cuenta de utilización a 0 */ - const int n = a_directory.size() - a_holes.size(); - result += a_name; - result += " | N: "; - result += functions::asString(a_maxSize); - result += " | n: "; - result += functions::asString(n); - result += " | r: "; - result += functions::asString(a_directory.size()); - result += " | AccessMode: "; - result += AccessMode::asString(a_accessMode); - result += " | Holes: "; - result += functions::asString(a_holes.size()); - result += " | Reuse: "; - result += functions::asString(a_doneReuse); - result += " | Hit: "; - result += functions::asString(a_hit); - result += " | Fault: "; - result += functions::asString(a_fault); - result += " | Ratio: "; - result += functions::asString(ratio); - return result += "% }"; -} - -xml::Node* StorageArea::asXML(xml::Node* parent) const -throw() { - xml::Node* result = parent->createChild("dbos.StorageArea"); - xml::Node* node; - const int ratio = (a_hit == 0) ? 0 : (a_hit * 100) / (a_fault + a_hit); - result->createAttribute("Name", a_name); - result->createAttribute("AccessMode", AccessMode::asString(a_accessMode)); - node = result->createChild("Size"); - node->createAttribute("Value", a_directory.size() - a_holes.size()); - node->createAttribute("Reserve", a_directory.size()); - node->createAttribute("MaxValue", a_maxSize); - node->createAttribute("Holes", a_holes.size()); - node = result->createChild("SizeOf"); - node->createAttribute("Value", asMemorySize(getSizeOf())); - node->createAttribute("MaxValue", asMemorySize(getMaxSizeOf())); - node = result->createChild("Statistics"); - node->createAttribute("Hit", a_hit); - node->createAttribute("Fault", a_fault); - node->createAttribute("Ratio", anna::functions::asString("%d%%", ratio)); - node->createAttribute("DoneReuse", a_doneReuse); - return result; -} - -string StorageArea::asMemorySize(const Size size) -throw() { - string result; - - if(size < 1024) { - result = functions::asString("%u bytes", size); - } else if(size < 1024 * 1024) { - static const Size ka = 1024; - result += functions::asString("%u Kb", size / ka); - } else { - static const Size mega = 1024 * 1024; - result += functions::asString("%u Mb", size / mega); - } - - return result; -} - -StorageArea::Instance* StorageArea::allocate() -throw() { - Instance* result = NULL; - - if((result = reuse()) == NULL) { - if((result = a_currentBlock->getInstance()) == NULL) { - if(++ a_indexBlock == a_blocks.size()) - a_blocks.push_back(a_currentBlock = new Block(a_objectAllocator, a_maxSize)); - else - a_currentBlock = a_blocks [a_indexBlock]; - - result = a_currentBlock->getInstance(); - } - } - - result->copyCounter = 1; -//xxx result->msHoleTime = 0; - result->flags = Flag::None; -//xxx result->hasHole = false; - return result; -} - -//----------------------------------------------------------------------------------------------------- -// Reusa un objeto que lleva demasiado tiempo sin ser utilizado. -// -// (0) Si el tiempo que lleva en la lista de objetos liberados es cero => Podemos usar el re-usado -// rapido; ya ha sido eliminado del directorio, invoca al destroy, etc, etc. -// (0.1) Para asegurar que NO desborde los 32 bits. -// (1) Cuando n -> Nmax => Talpha = now => a poco tiempo que pase sin reusar los registros, estos -// se comienzan a resuar. Cuando n -> 0 => talpha = 0 => No se reusan registros, sino que se crearan -// nuevos. -// (2) Si el primero de los registros disponibles no es suficientemente antiguo => no hay huecos libres -//----------------------------------------------------------------------------------------------------- -StorageArea::Instance* StorageArea::reuse() -throw() { - if(a_holes.empty() == true) - return NULL; - - Instance* result = NULL; - Instance* front = a_holes.front(); - bool quickReuse; - - if((front->flags & Flag::Ready) == false) { - if(a_directory.size() >= a_maxSize) { // El directorio contiene los que tienen cuenta 0 + los que están activos. - result = front; - iterator ii = a_directory.find(result->object->getIndex()); - - if(ii != a_directory.end()) - a_directory.erase(ii); - - if((result->flags & Flag::Empty) == 0) { - LOGINFORMATION( - string msg("Destroy (reuse) | "); - msg += asString(); - msg += " | "; - msg += asString(result); - Logger::information(msg, ANNA_FILE_LOCATION); - ); - result->object->destroy(); - result->flags &= Flag::NoEmpty; - } - } - - quickReuse = false; - } else { - // Si la entrada se cargó en los huecos como "usado rápido" se toma - result = front; - quickReuse = true; - } - - if(result != NULL) { - a_doneReuse ++; - result->flags &= Flag::NoReady; - result->flags &= Flag::NoHasHole; - a_holes.pop_front(); - } - - LOGDEBUG( - string msg("dbos::StorageArea::reuse | "); - msg += asString(); - msg += " | "; - msg += StorageArea::asString(result); - msg += functions::asText(" | QuickReuse: ", quickReuse); - Logger::debug(msg, ANNA_FILE_LOCATION); - ); - return result; -} - -std::string StorageArea::asString(const Instance* instance) -throw() { - std::string result("Instance { "); - - if(instance == NULL) - return result += " } "; - - result += "Reference: "; - result += functions::asHexString(anna_ptrnumber_cast(instance->object)); - result += " | Index: "; - result += functions::asHexString(instance->object->getIndex()); - result += functions::asText(" | Stored: ", instance->object->a_isStored); - result += " | CopyCounter: "; - result += functions::asString((unsigned int) instance->copyCounter); - result += " | Flags ("; - result += functions::asHexString(instance->flags); - result += "):"; - - if(instance->flags == Flag::None) - result += " None"; - else { - if(instance->flags & Flag::Dirty) - result += " Dirty"; - - if(instance->flags & Flag::Incoherent) - result += " Incoherent"; - - if(instance->flags & Flag::Empty) - result += " Empty"; - - if(instance->flags & Flag::HasHole) - result += " HasHole"; - - if(instance->flags & Flag::InProgress) - result += " InProgress"; - - result += (instance->flags & Flag::Ready) ? " Ready" : " TimeWait"; - } - - return result += " }"; -} - -const char* StorageArea::AccessMode::asString(const AccessMode::_v v) -throw() { - static const char* text [] = { "ReadOnly", "ReadWrite", "ReadEver" }; - return text [v]; -} - -/**************************************************************************************** -* Bloque de memoria. -****************************************************************************************/ -StorageArea::Block::Block(ObjectAllocator objectAllocator, const Size maxSize) : - a_size(0) { - a_maxSize = std::min(8U, std::max(256U, maxSize >> 7)); - a_instances = new Instance [a_maxSize]; - - for(int i = 0; i < a_maxSize; i ++) - a_instances [i].object = (*objectAllocator)(); -} - -bool StorageArea::Holes::insert(Instance* instance, const StorageArea::Holes::Mode::_v mode) -throw() { - if(instance->copyCounter > 0) - return false; - - /* Si la instancia ya ha sido registrada en la lista de huecos, sale sin más */ - if((instance->flags & Flag::HasHole) == true) - return true; - - switch(mode) { - case Mode::ReadyToReuse: - instance->holeIterator = a_holes.insert(a_holes.begin(), instance); - instance->flags |= Flag::HasHole; - instance->flags |= Flag::Ready; - a_size ++; - break; - case Mode::TimeWait: - instance->holeIterator = a_holes.insert(a_holes.end(), instance); - instance->flags |= Flag::HasHole; - instance->flags &= Flag::NoReady; - a_size ++; - break; - } - - LOGLOCAL6( - string msg("dbos::StorageArea::Holes::insert | This: "); - msg += functions::asHexString(anna_ptrnumber_cast(this)); - msg += " | "; - msg += StorageArea::asString(instance); - Logger::write(Logger::Local6, msg, ANNA_FILE_LOCATION); - ); - return true; -} - -void StorageArea::Holes::erase(Instance* instance) -throw() { - // instance->msHoleTime = 0; - instance->flags |= Flag::Ready; - - if(instance->copyCounter != 0) - return; - - /* Si la instancia NO ha sido registrada en la lista de huecos, sale sin más */ - if((instance->flags & Flag::HasHole) == false) - return; - - LOGLOCAL6( - string msg("dbos::StorageArea::Holes::erase | This: "); - msg += functions::asHexString(anna_ptrnumber_cast(this)); - msg += " | "; - msg += StorageArea::asString(instance); - Logger::write(Logger::Local6, msg, ANNA_FILE_LOCATION); - ); - a_holes.erase(instance->holeIterator); - instance->flags &= Flag::NoHasHole; - a_size --; -} - -/**************************************************************************************** -* Iterador - -class A { -public: - A () : a (0) { cout << "C0: " << (int) this << endl; } - A (const int _a): a (_a) { cout << "C1: " << (int) this << " " << a << endl; } - A (const A& other) : a (other.a) { cout << "C2: " << (int) this << " " << a << endl; } - - A& operator = (const A& other) { - cout << "CP: " << (int) this << " " << (a = other.a) << endl; - return *this; - } - - int get () const { return a; } -private: - int a; -}; - -A fx () { return A (2000); } - -int main () -{ - A aa = 100; - A bb (200); - A xx = aa; - A cc = fx (); - - cout << "CC: " << (int) &cc << " " << cc.get () << endl; - -} - -La salida del programucho es la siguiente: - -C1: -4198808 100 -C1: -4198812 200 -C2: -4198816 100 -C1: -4198820 2000 -CC: -4198820 2000 - -Lo que quiere decir que la "cc" la crea directamente sobre la pila y la asigna en fx sin aplicar ningn -otro constructor. - -Por eso cuando hac� StorageArea::Iterator ii = xxx->begin (), maxi = xxx->end (); ..... -no estaba pasando por el contructor copia ni por ningn otro constructor. - -****************************************************************************************/ -// Dejo todo el ejemplo para que sirva de recordatorio. -