1 // ANNA - Anna is Not Nothingness Anymore //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
13 #include <anna/core/tracing/Logger.hpp>
14 #include <anna/core/functions.hpp>
16 #include <anna/dbms/dbms.hpp>
17 #include <anna/dbos/dbos.hpp>
19 #include <anna/xml/Node.hpp>
20 #include <anna/xml/Attribute.hpp>
25 StorageArea::StorageArea(const char* name, const Size maxSize, ObjectAllocator objectAllocator, const StorageArea::AccessMode::_v accessMode, const int errorCode) :
28 a_objectAllocator(objectAllocator),
29 a_accessMode(accessMode),
30 a_errorCode(errorCode),
34 a_blocks.push_back(a_currentBlock = new Block(objectAllocator, maxSize));
38 StorageArea::~StorageArea() {
41 //------------------------------------------------------------------------------------------------
42 // Carga los datos del objeto y los guarda en el area de almacemiento.
44 // (1) Si no esta en memoria => se carga.
45 // (1.1) Si el registro no existe => se progresa la posible excepcion.
47 // (2) Cambia la politica de refresco de las areas de almacenamiento ReadWrite/Dirty. La carga solo se
48 // realizara cuando la copia de utilizacion sea 0. Ademas de la mejora de rendimiento aseguramos que
49 // la estabilidad de una instancia se mantiene durante toda la vida de esta. Por ejmplo evitamos que
50 // una instancia A este trabajando con una copia de una instancia que estamos liberando y volviendo
51 // a cargar con datos totalmente distintos ... imaginad que estamos recorriendo un vector asociado
54 // (3) Si no ha podido ser recargada (seguramente tiene mas de una referencia) debe evitar el
55 // uso en caso de que este marcada como Dirty.
56 // (4) Si el contador de uso es cero => que ya esta marcado como memoria libre, pero recordar que
57 // tambien puede estar en la memoria activa (pendiente de liberar y/o volver a usar). En este
58 // caso se ha reusado.
59 //------------------------------------------------------------------------------------------------
60 Object* StorageArea::instance(Connection* connection, Loader& loader)
61 throw(RuntimeException, DatabaseException) {
62 const Index index = loader.getIndex();
64 Instance* instance(NULL);
66 string msg("Instantiate (init) | ");
69 msg += loader.asString();
71 msg += functions::asHexString(index);
72 Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION)
74 loader.a_connection = connection;
75 std::string name("dbos::StorageArea::instance with ");
76 name += typeid(loader).name();
77 Guard guard(this, name.c_str());
78 iterator ii = a_directory.find(index);
80 if(ii == a_directory.end()) { // (1)
83 if(loader.load(connection, this) == true) { // (1.1)
84 pair <iterator, bool> rr;
85 bool wasInserted = false;
86 instance = allocate();
89 instance->object->setIndex(index);
90 /* Al añadir la instancia antes de invocar al método Object::initialize
91 * nos aseguramos de que se permitan implementar relaciones circulares
93 rr = a_directory.insert(value_type(index, instance));
95 result = instance->object;
96 instance->flags |= Flag::InProgress;
97 instance->object->initialize(loader);
98 instance->object->a_isStored = true;
99 instance->flags &= Flag::Done;
100 } catch(DatabaseException&) {
101 instance->flags &= Flag::Done;
104 a_directory.erase(rr.first);
106 a_holes.insert(instance, Holes::Mode::ReadyToReuse);
108 } catch(RuntimeException&) {
109 instance->flags &= Flag::Done;
112 a_directory.erase(rr.first);
114 a_holes.insert(instance, Holes::Mode::ReadyToReuse);
119 static const bool IgnoreDirty = true;
120 verifyStatus(instance = StorageArea::instance(ii), IgnoreDirty);
122 switch(a_accessMode) {
123 case AccessMode::ReadOnly:
124 result = ((instance->flags & Flag::Dirty) == 0) ? instance->object : reload(connection, loader, instance);
126 case AccessMode::ReadWrite:
127 result = (instance->copyCounter > 0) ? instance->object : reload(connection, loader, instance);
129 case AccessMode::ReadEver:
130 result = reload(connection, loader, instance);
134 if(instance->flags & Flag::Dirty) { // (3)
135 string msg(asString());
137 msg += asString(instance);
138 msg += " | Instance selected as unusable";
139 throw RuntimeException(msg, ANNA_FILE_LOCATION);
143 a_holes.erase(instance); // (4)
144 instance->copyCounter ++;
150 string msg("Instantiate (final) | ");
153 msg += asString(instance);
154 Logger::information(msg, ANNA_FILE_LOCATION)
159 Object* StorageArea::instance(Connection* connection, CrossedLoader& crossedLoader, Loader& loader)
160 throw(RuntimeException, DatabaseException) {
161 Object* result = NULL;
162 crossedLoader.a_connection = connection;
163 // Si el seek devuelve 'true' es que ya tiene cargada la correspondencia entre la clave alternativa y la
164 // clave principal usada en el Loader recibido como parámetro.
165 bool loaded = (crossedLoader.seek() == false) ? crossedLoader.load(connection, this) : true;
169 * Transfiere la clave principal conseguida por el cargador cruzado.
171 loader.upload(crossedLoader);
172 result = instance(connection, loader);
174 * Da la posibilidad de que el cargador cruzado mantenga la correspondencia entre sus claves y las claves primarias
176 crossedLoader.download(loader);
182 //-------------------------------------------------------------------------
183 // Crea un nuevo objeto en el area de almacenamiento.
184 //-------------------------------------------------------------------------
185 Object* StorageArea::create(Connection* connection, Creator& creator)
186 throw(RuntimeException, DatabaseException) {
187 const Index index = creator.getIndex();
188 Instance* instance = NULL;
189 Object* result = NULL;
191 if(a_accessMode == AccessMode::ReadOnly) {
192 string msg(asString());
193 msg += " | Cannot create object with AccessMode::ReadOnly";
194 throw RuntimeException(msg, ANNA_FILE_LOCATION);
198 string msg(asString());
200 msg += creator.asString();
202 msg += functions::asHexString(index);
203 Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION)
205 creator.a_connection = connection;
206 std::string name("dbos::StorageArea::create with ");
207 name += typeid(creator).name();
208 Guard guard(this, name.c_str());
209 iterator ii = a_directory.find(index);
211 if(ii == a_directory.end()) {
212 pair <iterator, bool> rr;
213 bool wasInserted = false;
215 instance = allocate();
218 instance->object->setIndex(index);
219 instance->copyCounter = 1;
220 result = instance->object;
221 rr = a_directory.insert(value_type(index, instance));
223 instance->flags |= Flag::InProgress;
224 instance->object->create(creator);
225 instance->flags &= Flag::Done;
226 instance->object->a_isStored = false;
227 } catch(DatabaseException&) {
228 instance->flags &= Flag::Done;
231 a_directory.erase(rr.first);
233 a_holes.insert(instance, Holes::Mode::ReadyToReuse);
235 } catch(RuntimeException&) {
236 instance->flags &= Flag::Done;
239 a_directory.erase(rr.first);
241 a_holes.insert(instance, Holes::Mode::ReadyToReuse);
245 verifyStatus(instance = StorageArea::instance(ii));
247 a_holes.erase(instance);
248 instance->copyCounter ++;
249 result = instance->object;
253 string msg("Create | ");
256 msg += asString(instance);
257 Logger::information(msg, ANNA_FILE_LOCATION)
262 //-------------------------------------------------------------------------
263 // Carga los datos del objeto y los guarda en el area de almacemiento.
265 // (1) Si tiene cuenta 0 => estaba en la lista de objetos liberados =>
267 //-------------------------------------------------------------------------
268 Object* StorageArea::find(Loader& loader)
269 throw(RuntimeException) {
270 const Index index = loader.getIndex();
271 Instance* instance = NULL;
272 Object* result = NULL;
274 string msg(asString());
276 msg += loader.asString();
278 msg += functions::asHexString(index);
279 Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION)
281 std::string name("dbos::StorageArea::find with ");
282 name += typeid(loader).name();
283 Guard guard(this, name.c_str());
284 iterator ii = a_directory.find(index);
286 if(ii != a_directory.end()) {
287 verifyStatus(instance = StorageArea::instance(ii));
289 a_holes.erase(instance);
290 instance->copyCounter ++;
291 result = instance->object;
296 string msg("Find | ");
299 msg += asString(instance);
300 Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION)
305 Object* StorageArea::duplicate(const Object* object)
306 throw(RuntimeException) {
307 if(object == NULL) return NULL;
309 std::string name("dbos::StorageArea::duplicate with ");
310 name += typeid(*object).name();
311 Guard guard(this, name.c_str());
312 iterator ii = a_directory.find(object->getIndex());
314 if(ii == a_directory.end()) {
316 string msg(asString());
318 msg += functions::asHexString(object->getIndex());
319 msg += " | Invalid instance";
320 throw RuntimeException(msg, ANNA_FILE_LOCATION);
323 Instance* instance = NULL;
324 verifyStatus(instance = StorageArea::instance(ii));
325 a_holes.erase(instance);
326 instance->copyCounter ++;
329 string msg("Duplicate | ");
332 msg += asString(instance);
333 Logger::information(msg, ANNA_FILE_LOCATION)
335 return instance->object;
338 bool StorageArea::isLoaded(const Loader& loader)
339 throw(RuntimeException) {
340 const Index index = loader.getIndex();
341 std::string name("dbos::StorageArea::isLoaded with ");
342 name += typeid(loader).name();
343 Guard guard(this, name.c_str());
344 iterator ii = a_directory.find(index);
345 const bool result = (ii != a_directory.end());
347 string msg(asString());
349 msg += loader.asString();
351 msg += functions::asHexString((int) index);
352 msg += functions::asText(" | isLoaded: ", result);
353 Logger::debug(msg, ANNA_FILE_LOCATION);
358 void StorageArea::apply(Connection& connection, Recorder& recorder)
359 throw(RuntimeException, DatabaseException) {
360 ResultCode resultCode = connection.execute(recorder.getStatement());
362 if(resultCode.successful() == false)
363 throw DatabaseException(resultCode, ANNA_FILE_LOCATION);
366 //------------------------------------------------------------------------------------------------
367 // Borra un objeto del medio fisico => lo borra tambien de la cache
369 // (1) Como copyCounter = 0 => Lo metera en lista de huecos, le quitara del directorio y
370 // si fuera necesario invocara al 'destroy'.
371 // (2) No la puede sacar de la memoria porque tiene referencias activas, pero por lo menos la
372 // marca como no usable para intentar provocar los avisos de uso incorrecto y expulsar la
373 // instancia en cuanto pueda.
374 //------------------------------------------------------------------------------------------------
375 void StorageArea::apply(Connection& connection, Eraser& eraser)
376 throw(RuntimeException, DatabaseException) {
377 if(a_accessMode == AccessMode::ReadOnly) {
378 string msg(asString());
379 msg += " | Cannot erase object with AccessMode::ReadOnly";
380 throw RuntimeException(msg, ANNA_FILE_LOCATION);
383 Object* object = eraser.getObject();
384 eraser.a_connection = &connection;
385 std::string name("dbos::StorageArea::apply with ");
386 name += typeid(eraser).name();
387 Guard guard(this, name.c_str());
388 Instance* instance = NULL;
391 iterator ii = a_directory.find(object->getIndex());
393 if(ii != a_directory.end()) {
394 instance = StorageArea::instance(ii);
396 if(instance->copyCounter > 1) {
397 instance->flags |= Flag::Incoherent; // (2)
398 string msg(eraser.asString());
399 msg += " | Instances: ";
400 msg += functions::asString(instance->copyCounter);
401 msg += " | Cannot delete object";
402 throw RuntimeException(msg, ANNA_FILE_LOCATION);
407 ResultCode resultCode = connection.execute(eraser.getStatement());
409 if(resultCode.successful() == false)
410 throw DatabaseException(resultCode, ANNA_FILE_LOCATION);
412 if(instance != NULL) {
413 instance->copyCounter = 0;
414 quickReusing(instance); // (1)
418 //------------------------------------------------------------------------------------------------
419 // Decrementa la cuenta de utilizacin del objeto recibido como parametro.
421 // (1) Si la instancia que estamos liberando esta marcada como 'Incoherente' y es la ultima
422 // referencia => es el momento de expulsarla de la memoria.
423 // (2) Queda a la espera de que se vuelva a usar la referencia o que el numero de registros en
424 // memoria alcance un numero tal que implique comenzar a reusar objetos liberados.
425 //------------------------------------------------------------------------------------------------
426 void StorageArea::release(Object** object)
427 throw(RuntimeException) {
428 if(object == NULL) return;
430 if(*object == NULL) return;
432 std::string name("dbos::StorageArea::release with ");
433 name += typeid(**object).name();
434 Guard guard(this, name.c_str());
435 iterator ii = a_directory.find((*object)->getIndex());
437 if(ii == a_directory.end())
440 Instance* instance = StorageArea::instance(ii);
442 if(instance->copyCounter > 0) {
443 if(-- instance->copyCounter == 0) {
444 if(instance->flags & Flag::Incoherent) // (1)
445 quickReusing(instance);
447 a_holes.insert(instance, Holes::Mode::TimeWait); // (2)
452 string msg("Release | ");
455 msg += asString(instance);
456 Logger::information(msg, ANNA_FILE_LOCATION)
461 //------------------------------------------------------------------------------------------------
462 // Elimina toda la informacin referente al objeto recibido como parametro.
464 // (1) No la puede sacar de la memoria porque tiene referencias activas, pero por lo menos la
465 // marca como no usable para intentar provocar los avisos de uso incorrecto y expulsar la
466 // instancia en cuanto pueda.
467 // (2) Como copyCounter = 0 => Lo metera en lista de huecos, le quitara del directorio y
468 // si fuera necesario invocara al 'destroy'.
469 //------------------------------------------------------------------------------------------------
470 void StorageArea::erase(Object** object)
471 throw(RuntimeException) {
472 if(object == NULL) return;
474 if(*object == NULL) return;
476 std::string name("dbos::StorageArea::erase with ");
477 name += typeid(**object).name();
478 Guard guard(this, name.c_str());
479 iterator ii = a_directory.find((*object)->getIndex());
481 if(ii == a_directory.end())
484 Instance* instance = StorageArea::instance(ii);
486 if(instance->copyCounter > 1) {
487 instance->flags |= Flag::Incoherent; // (1)
488 string msg(asString());
490 msg += asString(instance);
491 msg += " | Cannot dump instance";
492 throw RuntimeException(msg, ANNA_FILE_LOCATION);
496 string msg("Erase | ");
499 msg += asString(instance);
500 Logger::debug(msg, ANNA_FILE_LOCATION)
502 instance->copyCounter = 0;
503 quickReusing(instance); // (2)
507 void StorageArea::dirty(Object* object)
508 throw(RuntimeException) {
509 if(object == NULL) return;
511 std::string name("dbos::StorageArea::dirty with ");
512 name += typeid(*object).name();
513 Guard guard(this, name.c_str());
514 iterator ii = a_directory.find(object->getIndex());
516 if(ii == a_directory.end())
519 Instance* instance = StorageArea::instance(ii);
521 if(instance->copyCounter > 1 && Logger::isActive(Logger::Warning)) {
522 string msg(asString());
524 msg += asString(instance);
525 msg += " | More than one copy on instance to be selected";
526 Logger::warning(msg, ANNA_FILE_LOCATION);
530 string msg("Dirty | ");
533 msg += asString(instance);
534 Logger::debug(msg, ANNA_FILE_LOCATION)
538 //--------------------------------------------------------------------------------------------
539 // Descarga todos los objetos de este area de almacenamiento.
541 // (1) Para que permite incluirla en los huecos.
542 // (3) Si fuera necesario invoca al destroy => cuando se reuse no tendra que hacerlo.
543 // (4) Si la entrada estaba marcada como 'incoherente' la desmarca, ya que hemos conseguido
544 // expulsarla de cache.
545 //--------------------------------------------------------------------------------------------
546 void StorageArea::clear()
547 throw(RuntimeException) {
548 Guard guard(this, "dbos::StorageArea::clear");
552 for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++) {
553 instance = StorageArea::instance(ii);
554 instance->copyCounter = 0; // (1)
555 a_holes.insert(instance, Holes::Mode::ReadyToReuse);
557 if((instance->flags & Flag::Empty) == 0) { // (3)
559 string msg("Destroy (clear) | ");
562 msg += asString(instance);
563 Logger::information(msg, ANNA_FILE_LOCATION);
565 instance->object->destroy();
566 instance->flags |= Flag::Empty;
569 instance->flags &= Flag::NoIncoherent; // (4)
575 string msg("Clear | ");
577 msg += functions::asText(" | Destroyed objects: ", n);
578 Logger::warning(msg, ANNA_FILE_LOCATION)
582 //---------------------------------------------------------------------------------------------------
583 // Intenta recargar la informacion del medio fisico en la instancia del objeto.
584 // Si hay algun problema y la instancia no puede guardarse en la de objetos disponibles
585 // (a_holes.insert == false) => se marca como corrupto y no se podra usar hasta que
586 // que no se libere su ultima instancia.
588 // (1) Si hubiera algun problema al invocar al 'initialize' no habria que volver a invocar
590 // (2) Recordar que la recarga solo se intenta cuando la copyCounter = 0, por tanto en el caso de
591 // intentar recargar un registro que ha sido borrado no se vuelve a grabar como Ready porque
592 // YA esta en la lista de huecos y seria necesario borrarlo de esta, cambiarle el msHoleTime y
593 // volverlo a grabar, pero la cosa funciona porque se saca del directorio de objetos cargados
594 // y se libera su memoria.
595 //---------------------------------------------------------------------------------------------------
596 Object* StorageArea::reload(dbms::Connection* connection, Loader& loader, StorageArea::Instance* instance)
597 throw(RuntimeException, dbms::DatabaseException) {
598 const bool enableUpdate = (instance->flags & Flag::Dirty) ? true : instance->object->enableUpdate();
599 bool hasChanges(false);
601 if(enableUpdate == true) {
603 if(loader.load(connection, this) == false) {
604 checkIncoherence(instance); // (2)
607 } catch(RuntimeException&) {
608 checkIncoherence(instance);
610 } catch(dbms::DatabaseException&) {
611 checkIncoherence(instance);
615 hasChanges = (instance->flags & Flag::Dirty) ? true : instance->object->hasChanges(loader);
619 string msg("Reload | ");
622 msg += asString(instance);
623 msg += anna::functions::asText(" | EnableUpdate: ", enableUpdate);
624 msg += anna::functions::asText(" | HasChanges: ", hasChanges);
625 Logger::debug(msg, ANNA_FILE_LOCATION);
628 if(hasChanges == true) {
630 string msg("Destroy (reload) | ");
633 msg += asString(instance);
634 Logger::information(msg, ANNA_FILE_LOCATION);
636 instance->object->destroy();
637 instance->flags |= Flag::Empty; // (1)
638 instance->object->initialize(loader);
639 instance->flags &= Flag::NoEmpty;
640 instance->flags &= Flag::NoDirty;
643 return instance->object;
646 //------------------------------------------------------------------------------------------------
647 // Cuando intenta recargar la informacion de una instancia desde el medio fisico, pero el
648 // registro ha sido borrado =>
649 // 1.- Si hay alguna instancia en uso => no puede liberar la instancia porque algun otro
650 // objeto la tiene referenciada => la marca como corrupta.
651 // 2.- Si hay una unica instancia en uso => puede liberarla
653 // (1) si la puede grabar en los huecos o la instancia ya esta en los huecos => saca el objeto
654 // del directorio porque yo no es valido. Recupera la coherencia memoria-medio_fisico
655 // porque ha conseguido "expulsar" de la cache el registro borrado.
656 // (2) No puede "expulsar" el registro de la cache porque hay algun otro objeto que lo esta
657 // referenciando => Marca ESTA instancia como incoherente => no se podra duplicar y volver
658 // a instanciar, etc, etc
659 //------------------------------------------------------------------------------------------------
660 void StorageArea::checkIncoherence(StorageArea::Instance* instance)
662 if(quickReusing(instance) == true) {
664 string msg("dbos::StorageArea::checkIncoherence | ");
667 msg += asString(instance);
668 msg += " | Recover coherence between physical media and memory";
669 Logger::warning(msg, ANNA_FILE_LOCATION);
672 instance->flags |= Flag::Incoherent;
674 string msg("dbos::StorageArea::checkIncoherence | ");
677 msg += asString(instance);
678 msg += " | Detected incoherence between physical media and memory";
679 Logger::warning(msg, ANNA_FILE_LOCATION);
684 //------------------------------------------------------------------------------------------------
685 // (1) si la puede grabar en los huecos o la instancia ya esta en los huecos => (2)
686 // (2) saca el objeto del directorio porque yo no es valido.
687 // (3) Si fuera necesario invoca al destroy => cuando se reuse no tendra que hacerlo.
688 // (4) Si la entrada estaba marcada como 'incoherente' la desmarca, ya que hemos conseguido
689 // expulsarla de cache.
691 // Recordar que en el caso de intentar recargar un registro que ha sido borrado no se vuelve
692 // a grabar como Ready porque ya esta en la lista de huecos y seria necesario borrarlo de
693 // esta, cambiarle el msHoleTime y volverlo a grabar.
694 //------------------------------------------------------------------------------------------------
695 bool StorageArea::quickReusing(StorageArea::Instance* instance)
699 if(a_holes.insert(instance, Holes::Mode::ReadyToReuse) == true) { // (1)
700 iterator ii = a_directory.find(instance->object->getIndex());
702 if(ii != a_directory.end()) // (2)
703 a_directory.erase(ii);
705 if((instance->flags & Flag::Empty) == 0) { // (3)
707 string msg("Destroy (quickreusing) | ");
710 msg += asString(instance);
711 Logger::information(msg, ANNA_FILE_LOCATION);
713 instance->object->destroy();
714 instance->flags |= Flag::Empty;
717 instance->flags &= Flag::NoIncoherent; // (4)
724 void StorageArea::verifyStatus(StorageArea::Instance* instance, const bool ignoreDirty)
725 throw(RuntimeException) {
726 if(instance->flags & Flag::Incoherent) {
727 string msg(asString());
729 msg += asString(instance);
730 msg += " | Physical media and memory do not match";
731 throw RuntimeException(msg, ANNA_FILE_LOCATION);
734 if(instance->flags & Flag::Empty) {
735 string msg(asString());
737 msg += asString(instance);
738 msg += " | Instance is empty";
739 throw RuntimeException(msg, ANNA_FILE_LOCATION);
742 if(ignoreDirty == false && (instance->flags & Flag::Dirty)) {
743 string msg(asString());
745 msg += asString(instance);
746 msg += " | Instance is temporary locked";
747 throw RuntimeException(msg, ANNA_FILE_LOCATION);
750 if(instance->flags & Flag::InProgress) {
751 string msg(asString());
753 msg += asString(instance);
754 msg += " | Instance already has word in progress";
755 throw RuntimeException(msg, ANNA_FILE_LOCATION);
759 string StorageArea::asString() const
761 string result("dbos::StorageArea { Name: ");
762 const int ratio = (a_hit == 0) ? 0 : (a_hit * 100) / (a_fault + a_hit);
763 /* Nº real de objetos en uso. En el directorio también se mantienen los que tienen la cuenta de utilización a 0 */
764 const int n = a_directory.size() - a_holes.size();
767 result += functions::asString(a_maxSize);
769 result += functions::asString(n);
771 result += functions::asString(a_directory.size());
772 result += " | AccessMode: ";
773 result += AccessMode::asString(a_accessMode);
774 result += " | Holes: ";
775 result += functions::asString(a_holes.size());
776 result += " | Reuse: ";
777 result += functions::asString(a_doneReuse);
778 result += " | Hit: ";
779 result += functions::asString(a_hit);
780 result += " | Fault: ";
781 result += functions::asString(a_fault);
782 result += " | Ratio: ";
783 result += functions::asString(ratio);
784 return result += "% }";
787 xml::Node* StorageArea::asXML(xml::Node* parent) const
789 xml::Node* result = parent->createChild("dbos.StorageArea");
791 const int ratio = (a_hit == 0) ? 0 : (a_hit * 100) / (a_fault + a_hit);
792 result->createAttribute("Name", a_name);
793 result->createAttribute("AccessMode", AccessMode::asString(a_accessMode));
794 node = result->createChild("Size");
795 node->createAttribute("Value", a_directory.size() - a_holes.size());
796 node->createAttribute("Reserve", a_directory.size());
797 node->createAttribute("MaxValue", a_maxSize);
798 node->createAttribute("Holes", a_holes.size());
799 node = result->createChild("SizeOf");
800 node->createAttribute("Value", asMemorySize(getSizeOf()));
801 node->createAttribute("MaxValue", asMemorySize(getMaxSizeOf()));
802 node = result->createChild("Statistics");
803 node->createAttribute("Hit", a_hit);
804 node->createAttribute("Fault", a_fault);
805 node->createAttribute("Ratio", anna::functions::asString("%d%%", ratio));
806 node->createAttribute("DoneReuse", a_doneReuse);
810 string StorageArea::asMemorySize(const Size size)
815 result = functions::asString("%u bytes", size);
816 } else if(size < 1024 * 1024) {
817 static const Size ka = 1024;
818 result += functions::asString("%u Kb", size / ka);
820 static const Size mega = 1024 * 1024;
821 result += functions::asString("%u Mb", size / mega);
827 StorageArea::Instance* StorageArea::allocate()
829 Instance* result = NULL;
831 if((result = reuse()) == NULL) {
832 if((result = a_currentBlock->getInstance()) == NULL) {
833 if(++ a_indexBlock == a_blocks.size())
834 a_blocks.push_back(a_currentBlock = new Block(a_objectAllocator, a_maxSize));
836 a_currentBlock = a_blocks [a_indexBlock];
838 result = a_currentBlock->getInstance();
842 result->copyCounter = 1;
843 //xxx result->msHoleTime = 0;
844 result->flags = Flag::None;
845 //xxx result->hasHole = false;
849 //-----------------------------------------------------------------------------------------------------
850 // Reusa un objeto que lleva demasiado tiempo sin ser utilizado.
852 // (0) Si el tiempo que lleva en la lista de objetos liberados es cero => Podemos usar el re-usado
853 // rapido; ya ha sido eliminado del directorio, invoca al destroy, etc, etc.
854 // (0.1) Para asegurar que NO desborde los 32 bits.
855 // (1) Cuando n -> Nmax => Talpha = now => a poco tiempo que pase sin reusar los registros, estos
856 // se comienzan a resuar. Cuando n -> 0 => talpha = 0 => No se reusan registros, sino que se crearan
858 // (2) Si el primero de los registros disponibles no es suficientemente antiguo => no hay huecos libres
859 //-----------------------------------------------------------------------------------------------------
860 StorageArea::Instance* StorageArea::reuse()
862 if(a_holes.empty() == true)
865 Instance* result = NULL;
866 Instance* front = a_holes.front();
869 if((front->flags & Flag::Ready) == false) {
870 if(a_directory.size() >= a_maxSize) { // El directorio contiene los que tienen cuenta 0 + los que están activos.
872 iterator ii = a_directory.find(result->object->getIndex());
874 if(ii != a_directory.end())
875 a_directory.erase(ii);
877 if((result->flags & Flag::Empty) == 0) {
879 string msg("Destroy (reuse) | ");
882 msg += asString(result);
883 Logger::information(msg, ANNA_FILE_LOCATION);
885 result->object->destroy();
886 result->flags &= Flag::NoEmpty;
892 // Si la entrada se cargó en los huecos como "usado rápido" se toma
899 result->flags &= Flag::NoReady;
900 result->flags &= Flag::NoHasHole;
905 string msg("dbos::StorageArea::reuse | ");
908 msg += StorageArea::asString(result);
909 msg += functions::asText(" | QuickReuse: ", quickReuse);
910 Logger::debug(msg, ANNA_FILE_LOCATION);
915 std::string StorageArea::asString(const Instance* instance)
917 std::string result("Instance { ");
920 return result += "<null> } ";
922 result += "Reference: ";
923 result += functions::asHexString(anna_ptrnumber_cast(instance->object));
924 result += " | Index: ";
925 result += functions::asHexString(instance->object->getIndex());
926 result += functions::asText(" | Stored: ", instance->object->a_isStored);
927 result += " | CopyCounter: ";
928 result += functions::asString((unsigned int) instance->copyCounter);
929 result += " | Flags (";
930 result += functions::asHexString(instance->flags);
933 if(instance->flags == Flag::None)
936 if(instance->flags & Flag::Dirty)
939 if(instance->flags & Flag::Incoherent)
940 result += " Incoherent";
942 if(instance->flags & Flag::Empty)
945 if(instance->flags & Flag::HasHole)
946 result += " HasHole";
948 if(instance->flags & Flag::InProgress)
949 result += " InProgress";
951 result += (instance->flags & Flag::Ready) ? " Ready" : " TimeWait";
954 return result += " }";
957 const char* StorageArea::AccessMode::asString(const AccessMode::_v v)
959 static const char* text [] = { "ReadOnly", "ReadWrite", "ReadEver" };
963 /****************************************************************************************
965 ****************************************************************************************/
966 StorageArea::Block::Block(ObjectAllocator objectAllocator, const Size maxSize) :
968 a_maxSize = std::min(8U, std::max(256U, maxSize >> 7));
969 a_instances = new Instance [a_maxSize];
971 for(int i = 0; i < a_maxSize; i ++)
972 a_instances [i].object = (*objectAllocator)();
975 bool StorageArea::Holes::insert(Instance* instance, const StorageArea::Holes::Mode::_v mode)
977 if(instance->copyCounter > 0)
980 /* Si la instancia ya ha sido registrada en la lista de huecos, sale sin más */
981 if((instance->flags & Flag::HasHole) == true)
985 case Mode::ReadyToReuse:
986 instance->holeIterator = a_holes.insert(a_holes.begin(), instance);
987 instance->flags |= Flag::HasHole;
988 instance->flags |= Flag::Ready;
992 instance->holeIterator = a_holes.insert(a_holes.end(), instance);
993 instance->flags |= Flag::HasHole;
994 instance->flags &= Flag::NoReady;
1000 string msg("dbos::StorageArea::Holes::insert | This: ");
1001 msg += functions::asHexString(anna_ptrnumber_cast(this));
1003 msg += StorageArea::asString(instance);
1004 Logger::write(Logger::Local6, msg, ANNA_FILE_LOCATION);
1009 void StorageArea::Holes::erase(Instance* instance)
1011 // instance->msHoleTime = 0;
1012 instance->flags |= Flag::Ready;
1014 if(instance->copyCounter != 0)
1017 /* Si la instancia NO ha sido registrada en la lista de huecos, sale sin más */
1018 if((instance->flags & Flag::HasHole) == false)
1022 string msg("dbos::StorageArea::Holes::erase | This: ");
1023 msg += functions::asHexString(anna_ptrnumber_cast(this));
1025 msg += StorageArea::asString(instance);
1026 Logger::write(Logger::Local6, msg, ANNA_FILE_LOCATION);
1028 a_holes.erase(instance->holeIterator);
1029 instance->flags &= Flag::NoHasHole;
1033 /****************************************************************************************
1038 A () : a (0) { cout << "C0: " << (int) this << endl; }
1039 A (const int _a): a (_a) { cout << "C1: " << (int) this << " " << a << endl; }
1040 A (const A& other) : a (other.a) { cout << "C2: " << (int) this << " " << a << endl; }
1042 A& operator = (const A& other) {
1043 cout << "CP: " << (int) this << " " << (a = other.a) << endl;
1047 int get () const { return a; }
1052 A fx () { return A (2000); }
1061 cout << "CC: " << (int) &cc << " " << cc.get () << endl;
1065 La salida del programucho es la siguiente:
1073 Lo que quiere decir que la "cc" la crea directamente sobre la pila y la asigna en fx sin aplicar ningn
1076 Por eso cuando hac� StorageArea::Iterator ii = xxx->begin (), maxi = xxx->end (); .....
1077 no estaba pasando por el contructor copia ni por ningn otro constructor.
1079 ****************************************************************************************/
1080 // Dejo todo el ejemplo para que sirva de recordatorio.