-// 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 <typeinfo>
-
-#include <algorithm>
-
-#include <anna/core/tracing/Logger.hpp>
-#include <anna/core/functions.hpp>
-
-#include <anna/dbms/dbms.hpp>
-#include <anna/dbos/dbos.hpp>
-
-#include <anna/xml/Node.hpp>
-#include <anna/xml/Attribute.hpp>
-
-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 <iterator, bool> 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 <iterator, bool> 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 += "<null> } ";
-
- 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.
-