1 // ANNA - Anna is Not Nothingness Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // http://redmine.teslayout.com/projects/anna-suite
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
11 // * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
17 // * Neither the name of the copyright holder nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 // Authors: eduardo.ramos.testillano@gmail.com
34 // cisco.tierra@gmail.com
41 #include <anna/core/tracing/Logger.hpp>
42 #include <anna/core/functions.hpp>
44 #include <anna/dbms/dbms.hpp>
45 #include <anna/dbos/dbos.hpp>
47 #include <anna/xml/Node.hpp>
48 #include <anna/xml/Attribute.hpp>
53 StorageArea::StorageArea(const char* name, const Size maxSize, ObjectAllocator objectAllocator, const StorageArea::AccessMode::_v accessMode, const int errorCode) :
56 a_objectAllocator(objectAllocator),
57 a_accessMode(accessMode),
58 a_errorCode(errorCode),
62 a_blocks.push_back(a_currentBlock = new Block(objectAllocator, maxSize));
66 StorageArea::~StorageArea() {
69 //------------------------------------------------------------------------------------------------
70 // Carga los datos del objeto y los guarda en el area de almacemiento.
72 // (1) Si no esta en memoria => se carga.
73 // (1.1) Si el registro no existe => se progresa la posible excepcion.
75 // (2) Cambia la politica de refresco de las areas de almacenamiento ReadWrite/Dirty. La carga solo se
76 // realizara cuando la copia de utilizacion sea 0. Ademas de la mejora de rendimiento aseguramos que
77 // la estabilidad de una instancia se mantiene durante toda la vida de esta. Por ejmplo evitamos que
78 // una instancia A este trabajando con una copia de una instancia que estamos liberando y volviendo
79 // a cargar con datos totalmente distintos ... imaginad que estamos recorriendo un vector asociado
82 // (3) Si no ha podido ser recargada (seguramente tiene mas de una referencia) debe evitar el
83 // uso en caso de que este marcada como Dirty.
84 // (4) Si el contador de uso es cero => que ya esta marcado como memoria libre, pero recordar que
85 // tambien puede estar en la memoria activa (pendiente de liberar y/o volver a usar). En este
86 // caso se ha reusado.
87 //------------------------------------------------------------------------------------------------
88 Object* StorageArea::instance(Connection* connection, Loader& loader)
89 throw(RuntimeException, DatabaseException) {
90 const Index index = loader.getIndex();
92 Instance* instance(NULL);
94 string msg("Instantiate (init) | ");
97 msg += loader.asString();
99 msg += functions::asHexString(index);
100 Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION)
102 loader.a_connection = connection;
103 std::string name("dbos::StorageArea::instance with ");
104 name += typeid(loader).name();
105 Guard guard(this, name.c_str());
106 iterator ii = a_directory.find(index);
108 if(ii == a_directory.end()) { // (1)
111 if(loader.load(connection, this) == true) { // (1.1)
112 pair <iterator, bool> rr;
113 bool wasInserted = false;
114 instance = allocate();
117 instance->object->setIndex(index);
118 /* Al añadir la instancia antes de invocar al método Object::initialize
119 * nos aseguramos de que se permitan implementar relaciones circulares
121 rr = a_directory.insert(value_type(index, instance));
123 result = instance->object;
124 instance->flags |= Flag::InProgress;
125 instance->object->initialize(loader);
126 instance->object->a_isStored = true;
127 instance->flags &= Flag::Done;
128 } catch(DatabaseException&) {
129 instance->flags &= Flag::Done;
132 a_directory.erase(rr.first);
134 a_holes.insert(instance, Holes::Mode::ReadyToReuse);
136 } catch(RuntimeException&) {
137 instance->flags &= Flag::Done;
140 a_directory.erase(rr.first);
142 a_holes.insert(instance, Holes::Mode::ReadyToReuse);
147 static const bool IgnoreDirty = true;
148 verifyStatus(instance = StorageArea::instance(ii), IgnoreDirty);
150 switch(a_accessMode) {
151 case AccessMode::ReadOnly:
152 result = ((instance->flags & Flag::Dirty) == 0) ? instance->object : reload(connection, loader, instance);
154 case AccessMode::ReadWrite:
155 result = (instance->copyCounter > 0) ? instance->object : reload(connection, loader, instance);
157 case AccessMode::ReadEver:
158 result = reload(connection, loader, instance);
162 if(instance->flags & Flag::Dirty) { // (3)
163 string msg(asString());
165 msg += asString(instance);
166 msg += " | Instance selected as unusable";
167 throw RuntimeException(msg, ANNA_FILE_LOCATION);
171 a_holes.erase(instance); // (4)
172 instance->copyCounter ++;
178 string msg("Instantiate (final) | ");
181 msg += asString(instance);
182 Logger::information(msg, ANNA_FILE_LOCATION)
187 Object* StorageArea::instance(Connection* connection, CrossedLoader& crossedLoader, Loader& loader)
188 throw(RuntimeException, DatabaseException) {
189 Object* result = NULL;
190 crossedLoader.a_connection = connection;
191 // Si el seek devuelve 'true' es que ya tiene cargada la correspondencia entre la clave alternativa y la
192 // clave principal usada en el Loader recibido como parámetro.
193 bool loaded = (crossedLoader.seek() == false) ? crossedLoader.load(connection, this) : true;
197 * Transfiere la clave principal conseguida por el cargador cruzado.
199 loader.upload(crossedLoader);
200 result = instance(connection, loader);
202 * Da la posibilidad de que el cargador cruzado mantenga la correspondencia entre sus claves y las claves primarias
204 crossedLoader.download(loader);
210 //-------------------------------------------------------------------------
211 // Crea un nuevo objeto en el area de almacenamiento.
212 //-------------------------------------------------------------------------
213 Object* StorageArea::create(Connection* connection, Creator& creator)
214 throw(RuntimeException, DatabaseException) {
215 const Index index = creator.getIndex();
216 Instance* instance = NULL;
217 Object* result = NULL;
219 if(a_accessMode == AccessMode::ReadOnly) {
220 string msg(asString());
221 msg += " | Cannot create object with AccessMode::ReadOnly";
222 throw RuntimeException(msg, ANNA_FILE_LOCATION);
226 string msg(asString());
228 msg += creator.asString();
230 msg += functions::asHexString(index);
231 Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION)
233 creator.a_connection = connection;
234 std::string name("dbos::StorageArea::create with ");
235 name += typeid(creator).name();
236 Guard guard(this, name.c_str());
237 iterator ii = a_directory.find(index);
239 if(ii == a_directory.end()) {
240 pair <iterator, bool> rr;
241 bool wasInserted = false;
243 instance = allocate();
246 instance->object->setIndex(index);
247 instance->copyCounter = 1;
248 result = instance->object;
249 rr = a_directory.insert(value_type(index, instance));
251 instance->flags |= Flag::InProgress;
252 instance->object->create(creator);
253 instance->flags &= Flag::Done;
254 instance->object->a_isStored = false;
255 } catch(DatabaseException&) {
256 instance->flags &= Flag::Done;
259 a_directory.erase(rr.first);
261 a_holes.insert(instance, Holes::Mode::ReadyToReuse);
263 } catch(RuntimeException&) {
264 instance->flags &= Flag::Done;
267 a_directory.erase(rr.first);
269 a_holes.insert(instance, Holes::Mode::ReadyToReuse);
273 verifyStatus(instance = StorageArea::instance(ii));
275 a_holes.erase(instance);
276 instance->copyCounter ++;
277 result = instance->object;
281 string msg("Create | ");
284 msg += asString(instance);
285 Logger::information(msg, ANNA_FILE_LOCATION)
290 //-------------------------------------------------------------------------
291 // Carga los datos del objeto y los guarda en el area de almacemiento.
293 // (1) Si tiene cuenta 0 => estaba en la lista de objetos liberados =>
295 //-------------------------------------------------------------------------
296 Object* StorageArea::find(Loader& loader)
297 throw(RuntimeException) {
298 const Index index = loader.getIndex();
299 Instance* instance = NULL;
300 Object* result = NULL;
302 string msg(asString());
304 msg += loader.asString();
306 msg += functions::asHexString(index);
307 Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION)
309 std::string name("dbos::StorageArea::find with ");
310 name += typeid(loader).name();
311 Guard guard(this, name.c_str());
312 iterator ii = a_directory.find(index);
314 if(ii != a_directory.end()) {
315 verifyStatus(instance = StorageArea::instance(ii));
317 a_holes.erase(instance);
318 instance->copyCounter ++;
319 result = instance->object;
324 string msg("Find | ");
327 msg += asString(instance);
328 Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION)
333 Object* StorageArea::duplicate(const Object* object)
334 throw(RuntimeException) {
335 if(object == NULL) return NULL;
337 std::string name("dbos::StorageArea::duplicate with ");
338 name += typeid(*object).name();
339 Guard guard(this, name.c_str());
340 iterator ii = a_directory.find(object->getIndex());
342 if(ii == a_directory.end()) {
344 string msg(asString());
346 msg += functions::asHexString(object->getIndex());
347 msg += " | Invalid instance";
348 throw RuntimeException(msg, ANNA_FILE_LOCATION);
351 Instance* instance = NULL;
352 verifyStatus(instance = StorageArea::instance(ii));
353 a_holes.erase(instance);
354 instance->copyCounter ++;
357 string msg("Duplicate | ");
360 msg += asString(instance);
361 Logger::information(msg, ANNA_FILE_LOCATION)
363 return instance->object;
366 bool StorageArea::isLoaded(const Loader& loader)
367 throw(RuntimeException) {
368 const Index index = loader.getIndex();
369 std::string name("dbos::StorageArea::isLoaded with ");
370 name += typeid(loader).name();
371 Guard guard(this, name.c_str());
372 iterator ii = a_directory.find(index);
373 const bool result = (ii != a_directory.end());
375 string msg(asString());
377 msg += loader.asString();
379 msg += functions::asHexString((int) index);
380 msg += functions::asText(" | isLoaded: ", result);
381 Logger::debug(msg, ANNA_FILE_LOCATION);
386 void StorageArea::apply(Connection& connection, Recorder& recorder)
387 throw(RuntimeException, DatabaseException) {
388 ResultCode resultCode = connection.execute(recorder.getStatement());
390 if(resultCode.successful() == false)
391 throw DatabaseException(resultCode, ANNA_FILE_LOCATION);
394 //------------------------------------------------------------------------------------------------
395 // Borra un objeto del medio fisico => lo borra tambien de la cache
397 // (1) Como copyCounter = 0 => Lo metera en lista de huecos, le quitara del directorio y
398 // si fuera necesario invocara al 'destroy'.
399 // (2) No la puede sacar de la memoria porque tiene referencias activas, pero por lo menos la
400 // marca como no usable para intentar provocar los avisos de uso incorrecto y expulsar la
401 // instancia en cuanto pueda.
402 //------------------------------------------------------------------------------------------------
403 void StorageArea::apply(Connection& connection, Eraser& eraser)
404 throw(RuntimeException, DatabaseException) {
405 if(a_accessMode == AccessMode::ReadOnly) {
406 string msg(asString());
407 msg += " | Cannot erase object with AccessMode::ReadOnly";
408 throw RuntimeException(msg, ANNA_FILE_LOCATION);
411 Object* object = eraser.getObject();
412 eraser.a_connection = &connection;
413 std::string name("dbos::StorageArea::apply with ");
414 name += typeid(eraser).name();
415 Guard guard(this, name.c_str());
416 Instance* instance = NULL;
419 iterator ii = a_directory.find(object->getIndex());
421 if(ii != a_directory.end()) {
422 instance = StorageArea::instance(ii);
424 if(instance->copyCounter > 1) {
425 instance->flags |= Flag::Incoherent; // (2)
426 string msg(eraser.asString());
427 msg += " | Instances: ";
428 msg += functions::asString(instance->copyCounter);
429 msg += " | Cannot delete object";
430 throw RuntimeException(msg, ANNA_FILE_LOCATION);
435 ResultCode resultCode = connection.execute(eraser.getStatement());
437 if(resultCode.successful() == false)
438 throw DatabaseException(resultCode, ANNA_FILE_LOCATION);
440 if(instance != NULL) {
441 instance->copyCounter = 0;
442 quickReusing(instance); // (1)
446 //------------------------------------------------------------------------------------------------
447 // Decrementa la cuenta de utilizacin del objeto recibido como parametro.
449 // (1) Si la instancia que estamos liberando esta marcada como 'Incoherente' y es la ultima
450 // referencia => es el momento de expulsarla de la memoria.
451 // (2) Queda a la espera de que se vuelva a usar la referencia o que el numero de registros en
452 // memoria alcance un numero tal que implique comenzar a reusar objetos liberados.
453 //------------------------------------------------------------------------------------------------
454 void StorageArea::release(Object** object)
455 throw(RuntimeException) {
456 if(object == NULL) return;
458 if(*object == NULL) return;
460 std::string name("dbos::StorageArea::release with ");
461 name += typeid(**object).name();
462 Guard guard(this, name.c_str());
463 iterator ii = a_directory.find((*object)->getIndex());
465 if(ii == a_directory.end())
468 Instance* instance = StorageArea::instance(ii);
470 if(instance->copyCounter > 0) {
471 if(-- instance->copyCounter == 0) {
472 if(instance->flags & Flag::Incoherent) // (1)
473 quickReusing(instance);
475 a_holes.insert(instance, Holes::Mode::TimeWait); // (2)
480 string msg("Release | ");
483 msg += asString(instance);
484 Logger::information(msg, ANNA_FILE_LOCATION)
489 //------------------------------------------------------------------------------------------------
490 // Elimina toda la informacin referente al objeto recibido como parametro.
492 // (1) No la puede sacar de la memoria porque tiene referencias activas, pero por lo menos la
493 // marca como no usable para intentar provocar los avisos de uso incorrecto y expulsar la
494 // instancia en cuanto pueda.
495 // (2) Como copyCounter = 0 => Lo metera en lista de huecos, le quitara del directorio y
496 // si fuera necesario invocara al 'destroy'.
497 //------------------------------------------------------------------------------------------------
498 void StorageArea::erase(Object** object)
499 throw(RuntimeException) {
500 if(object == NULL) return;
502 if(*object == NULL) return;
504 std::string name("dbos::StorageArea::erase with ");
505 name += typeid(**object).name();
506 Guard guard(this, name.c_str());
507 iterator ii = a_directory.find((*object)->getIndex());
509 if(ii == a_directory.end())
512 Instance* instance = StorageArea::instance(ii);
514 if(instance->copyCounter > 1) {
515 instance->flags |= Flag::Incoherent; // (1)
516 string msg(asString());
518 msg += asString(instance);
519 msg += " | Cannot dump instance";
520 throw RuntimeException(msg, ANNA_FILE_LOCATION);
524 string msg("Erase | ");
527 msg += asString(instance);
528 Logger::debug(msg, ANNA_FILE_LOCATION)
530 instance->copyCounter = 0;
531 quickReusing(instance); // (2)
535 void StorageArea::dirty(Object* object)
536 throw(RuntimeException) {
537 if(object == NULL) return;
539 std::string name("dbos::StorageArea::dirty with ");
540 name += typeid(*object).name();
541 Guard guard(this, name.c_str());
542 iterator ii = a_directory.find(object->getIndex());
544 if(ii == a_directory.end())
547 Instance* instance = StorageArea::instance(ii);
549 if(instance->copyCounter > 1 && Logger::isActive(Logger::Warning)) {
550 string msg(asString());
552 msg += asString(instance);
553 msg += " | More than one copy on instance to be selected";
554 Logger::warning(msg, ANNA_FILE_LOCATION);
558 string msg("Dirty | ");
561 msg += asString(instance);
562 Logger::debug(msg, ANNA_FILE_LOCATION)
566 //--------------------------------------------------------------------------------------------
567 // Descarga todos los objetos de este area de almacenamiento.
569 // (1) Para que permite incluirla en los huecos.
570 // (3) Si fuera necesario invoca al destroy => cuando se reuse no tendra que hacerlo.
571 // (4) Si la entrada estaba marcada como 'incoherente' la desmarca, ya que hemos conseguido
572 // expulsarla de cache.
573 //--------------------------------------------------------------------------------------------
574 void StorageArea::clear()
575 throw(RuntimeException) {
576 Guard guard(this, "dbos::StorageArea::clear");
580 for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++) {
581 instance = StorageArea::instance(ii);
582 instance->copyCounter = 0; // (1)
583 a_holes.insert(instance, Holes::Mode::ReadyToReuse);
585 if((instance->flags & Flag::Empty) == 0) { // (3)
587 string msg("Destroy (clear) | ");
590 msg += asString(instance);
591 Logger::information(msg, ANNA_FILE_LOCATION);
593 instance->object->destroy();
594 instance->flags |= Flag::Empty;
597 instance->flags &= Flag::NoIncoherent; // (4)
603 string msg("Clear | ");
605 msg += functions::asText(" | Destroyed objects: ", n);
606 Logger::warning(msg, ANNA_FILE_LOCATION)
610 //---------------------------------------------------------------------------------------------------
611 // Intenta recargar la informacion del medio fisico en la instancia del objeto.
612 // Si hay algun problema y la instancia no puede guardarse en la de objetos disponibles
613 // (a_holes.insert == false) => se marca como corrupto y no se podra usar hasta que
614 // que no se libere su ultima instancia.
616 // (1) Si hubiera algun problema al invocar al 'initialize' no habria que volver a invocar
618 // (2) Recordar que la recarga solo se intenta cuando la copyCounter = 0, por tanto en el caso de
619 // intentar recargar un registro que ha sido borrado no se vuelve a grabar como Ready porque
620 // YA esta en la lista de huecos y seria necesario borrarlo de esta, cambiarle el msHoleTime y
621 // volverlo a grabar, pero la cosa funciona porque se saca del directorio de objetos cargados
622 // y se libera su memoria.
623 //---------------------------------------------------------------------------------------------------
624 Object* StorageArea::reload(dbms::Connection* connection, Loader& loader, StorageArea::Instance* instance)
625 throw(RuntimeException, dbms::DatabaseException) {
626 const bool enableUpdate = (instance->flags & Flag::Dirty) ? true : instance->object->enableUpdate();
627 bool hasChanges(false);
629 if(enableUpdate == true) {
631 if(loader.load(connection, this) == false) {
632 checkIncoherence(instance); // (2)
635 } catch(RuntimeException&) {
636 checkIncoherence(instance);
638 } catch(dbms::DatabaseException&) {
639 checkIncoherence(instance);
643 hasChanges = (instance->flags & Flag::Dirty) ? true : instance->object->hasChanges(loader);
647 string msg("Reload | ");
650 msg += asString(instance);
651 msg += anna::functions::asText(" | EnableUpdate: ", enableUpdate);
652 msg += anna::functions::asText(" | HasChanges: ", hasChanges);
653 Logger::debug(msg, ANNA_FILE_LOCATION);
656 if(hasChanges == true) {
658 string msg("Destroy (reload) | ");
661 msg += asString(instance);
662 Logger::information(msg, ANNA_FILE_LOCATION);
664 instance->object->destroy();
665 instance->flags |= Flag::Empty; // (1)
666 instance->object->initialize(loader);
667 instance->flags &= Flag::NoEmpty;
668 instance->flags &= Flag::NoDirty;
671 return instance->object;
674 //------------------------------------------------------------------------------------------------
675 // Cuando intenta recargar la informacion de una instancia desde el medio fisico, pero el
676 // registro ha sido borrado =>
677 // 1.- Si hay alguna instancia en uso => no puede liberar la instancia porque algun otro
678 // objeto la tiene referenciada => la marca como corrupta.
679 // 2.- Si hay una unica instancia en uso => puede liberarla
681 // (1) si la puede grabar en los huecos o la instancia ya esta en los huecos => saca el objeto
682 // del directorio porque yo no es valido. Recupera la coherencia memoria-medio_fisico
683 // porque ha conseguido "expulsar" de la cache el registro borrado.
684 // (2) No puede "expulsar" el registro de la cache porque hay algun otro objeto que lo esta
685 // referenciando => Marca ESTA instancia como incoherente => no se podra duplicar y volver
686 // a instanciar, etc, etc
687 //------------------------------------------------------------------------------------------------
688 void StorageArea::checkIncoherence(StorageArea::Instance* instance)
690 if(quickReusing(instance) == true) {
692 string msg("dbos::StorageArea::checkIncoherence | ");
695 msg += asString(instance);
696 msg += " | Recover coherence between physical media and memory";
697 Logger::warning(msg, ANNA_FILE_LOCATION);
700 instance->flags |= Flag::Incoherent;
702 string msg("dbos::StorageArea::checkIncoherence | ");
705 msg += asString(instance);
706 msg += " | Detected incoherence between physical media and memory";
707 Logger::warning(msg, ANNA_FILE_LOCATION);
712 //------------------------------------------------------------------------------------------------
713 // (1) si la puede grabar en los huecos o la instancia ya esta en los huecos => (2)
714 // (2) saca el objeto del directorio porque yo no es valido.
715 // (3) Si fuera necesario invoca al destroy => cuando se reuse no tendra que hacerlo.
716 // (4) Si la entrada estaba marcada como 'incoherente' la desmarca, ya que hemos conseguido
717 // expulsarla de cache.
719 // Recordar que en el caso de intentar recargar un registro que ha sido borrado no se vuelve
720 // a grabar como Ready porque ya esta en la lista de huecos y seria necesario borrarlo de
721 // esta, cambiarle el msHoleTime y volverlo a grabar.
722 //------------------------------------------------------------------------------------------------
723 bool StorageArea::quickReusing(StorageArea::Instance* instance)
727 if(a_holes.insert(instance, Holes::Mode::ReadyToReuse) == true) { // (1)
728 iterator ii = a_directory.find(instance->object->getIndex());
730 if(ii != a_directory.end()) // (2)
731 a_directory.erase(ii);
733 if((instance->flags & Flag::Empty) == 0) { // (3)
735 string msg("Destroy (quickreusing) | ");
738 msg += asString(instance);
739 Logger::information(msg, ANNA_FILE_LOCATION);
741 instance->object->destroy();
742 instance->flags |= Flag::Empty;
745 instance->flags &= Flag::NoIncoherent; // (4)
752 void StorageArea::verifyStatus(StorageArea::Instance* instance, const bool ignoreDirty)
753 throw(RuntimeException) {
754 if(instance->flags & Flag::Incoherent) {
755 string msg(asString());
757 msg += asString(instance);
758 msg += " | Physical media and memory do not match";
759 throw RuntimeException(msg, ANNA_FILE_LOCATION);
762 if(instance->flags & Flag::Empty) {
763 string msg(asString());
765 msg += asString(instance);
766 msg += " | Instance is empty";
767 throw RuntimeException(msg, ANNA_FILE_LOCATION);
770 if(ignoreDirty == false && (instance->flags & Flag::Dirty)) {
771 string msg(asString());
773 msg += asString(instance);
774 msg += " | Instance is temporary locked";
775 throw RuntimeException(msg, ANNA_FILE_LOCATION);
778 if(instance->flags & Flag::InProgress) {
779 string msg(asString());
781 msg += asString(instance);
782 msg += " | Instance already has word in progress";
783 throw RuntimeException(msg, ANNA_FILE_LOCATION);
787 string StorageArea::asString() const
789 string result("dbos::StorageArea { Name: ");
790 const int ratio = (a_hit == 0) ? 0 : (a_hit * 100) / (a_fault + a_hit);
791 /* Nº real de objetos en uso. En el directorio también se mantienen los que tienen la cuenta de utilización a 0 */
792 const int n = a_directory.size() - a_holes.size();
795 result += functions::asString(a_maxSize);
797 result += functions::asString(n);
799 result += functions::asString(a_directory.size());
800 result += " | AccessMode: ";
801 result += AccessMode::asString(a_accessMode);
802 result += " | Holes: ";
803 result += functions::asString(a_holes.size());
804 result += " | Reuse: ";
805 result += functions::asString(a_doneReuse);
806 result += " | Hit: ";
807 result += functions::asString(a_hit);
808 result += " | Fault: ";
809 result += functions::asString(a_fault);
810 result += " | Ratio: ";
811 result += functions::asString(ratio);
812 return result += "% }";
815 xml::Node* StorageArea::asXML(xml::Node* parent) const
817 xml::Node* result = parent->createChild("dbos.StorageArea");
819 const int ratio = (a_hit == 0) ? 0 : (a_hit * 100) / (a_fault + a_hit);
820 result->createAttribute("Name", a_name);
821 result->createAttribute("AccessMode", AccessMode::asString(a_accessMode));
822 node = result->createChild("Size");
823 node->createAttribute("Value", a_directory.size() - a_holes.size());
824 node->createAttribute("Reserve", a_directory.size());
825 node->createAttribute("MaxValue", a_maxSize);
826 node->createAttribute("Holes", a_holes.size());
827 node = result->createChild("SizeOf");
828 node->createAttribute("Value", asMemorySize(getSizeOf()));
829 node->createAttribute("MaxValue", asMemorySize(getMaxSizeOf()));
830 node = result->createChild("Statistics");
831 node->createAttribute("Hit", a_hit);
832 node->createAttribute("Fault", a_fault);
833 node->createAttribute("Ratio", anna::functions::asString("%d%%", ratio));
834 node->createAttribute("DoneReuse", a_doneReuse);
838 string StorageArea::asMemorySize(const Size size)
843 result = functions::asString("%u bytes", size);
844 } else if(size < 1024 * 1024) {
845 static const Size ka = 1024;
846 result += functions::asString("%u Kb", size / ka);
848 static const Size mega = 1024 * 1024;
849 result += functions::asString("%u Mb", size / mega);
855 StorageArea::Instance* StorageArea::allocate()
857 Instance* result = NULL;
859 if((result = reuse()) == NULL) {
860 if((result = a_currentBlock->getInstance()) == NULL) {
861 if(++ a_indexBlock == a_blocks.size())
862 a_blocks.push_back(a_currentBlock = new Block(a_objectAllocator, a_maxSize));
864 a_currentBlock = a_blocks [a_indexBlock];
866 result = a_currentBlock->getInstance();
870 result->copyCounter = 1;
871 //xxx result->msHoleTime = 0;
872 result->flags = Flag::None;
873 //xxx result->hasHole = false;
877 //-----------------------------------------------------------------------------------------------------
878 // Reusa un objeto que lleva demasiado tiempo sin ser utilizado.
880 // (0) Si el tiempo que lleva en la lista de objetos liberados es cero => Podemos usar el re-usado
881 // rapido; ya ha sido eliminado del directorio, invoca al destroy, etc, etc.
882 // (0.1) Para asegurar que NO desborde los 32 bits.
883 // (1) Cuando n -> Nmax => Talpha = now => a poco tiempo que pase sin reusar los registros, estos
884 // se comienzan a resuar. Cuando n -> 0 => talpha = 0 => No se reusan registros, sino que se crearan
886 // (2) Si el primero de los registros disponibles no es suficientemente antiguo => no hay huecos libres
887 //-----------------------------------------------------------------------------------------------------
888 StorageArea::Instance* StorageArea::reuse()
890 if(a_holes.empty() == true)
893 Instance* result = NULL;
894 Instance* front = a_holes.front();
897 if((front->flags & Flag::Ready) == false) {
898 if(a_directory.size() >= a_maxSize) { // El directorio contiene los que tienen cuenta 0 + los que están activos.
900 iterator ii = a_directory.find(result->object->getIndex());
902 if(ii != a_directory.end())
903 a_directory.erase(ii);
905 if((result->flags & Flag::Empty) == 0) {
907 string msg("Destroy (reuse) | ");
910 msg += asString(result);
911 Logger::information(msg, ANNA_FILE_LOCATION);
913 result->object->destroy();
914 result->flags &= Flag::NoEmpty;
920 // Si la entrada se cargó en los huecos como "usado rápido" se toma
927 result->flags &= Flag::NoReady;
928 result->flags &= Flag::NoHasHole;
933 string msg("dbos::StorageArea::reuse | ");
936 msg += StorageArea::asString(result);
937 msg += functions::asText(" | QuickReuse: ", quickReuse);
938 Logger::debug(msg, ANNA_FILE_LOCATION);
943 std::string StorageArea::asString(const Instance* instance)
945 std::string result("Instance { ");
948 return result += "<null> } ";
950 result += "Reference: ";
951 result += functions::asHexString(anna_ptrnumber_cast(instance->object));
952 result += " | Index: ";
953 result += functions::asHexString(instance->object->getIndex());
954 result += functions::asText(" | Stored: ", instance->object->a_isStored);
955 result += " | CopyCounter: ";
956 result += functions::asString((unsigned int) instance->copyCounter);
957 result += " | Flags (";
958 result += functions::asHexString(instance->flags);
961 if(instance->flags == Flag::None)
964 if(instance->flags & Flag::Dirty)
967 if(instance->flags & Flag::Incoherent)
968 result += " Incoherent";
970 if(instance->flags & Flag::Empty)
973 if(instance->flags & Flag::HasHole)
974 result += " HasHole";
976 if(instance->flags & Flag::InProgress)
977 result += " InProgress";
979 result += (instance->flags & Flag::Ready) ? " Ready" : " TimeWait";
982 return result += " }";
985 const char* StorageArea::AccessMode::asString(const AccessMode::_v v)
987 static const char* text [] = { "ReadOnly", "ReadWrite", "ReadEver" };
991 /****************************************************************************************
993 ****************************************************************************************/
994 StorageArea::Block::Block(ObjectAllocator objectAllocator, const Size maxSize) :
996 a_maxSize = std::min(8U, std::max(256U, maxSize >> 7));
997 a_instances = new Instance [a_maxSize];
999 for(int i = 0; i < a_maxSize; i ++)
1000 a_instances [i].object = (*objectAllocator)();
1003 bool StorageArea::Holes::insert(Instance* instance, const StorageArea::Holes::Mode::_v mode)
1005 if(instance->copyCounter > 0)
1008 /* Si la instancia ya ha sido registrada en la lista de huecos, sale sin más */
1009 if((instance->flags & Flag::HasHole) == true)
1013 case Mode::ReadyToReuse:
1014 instance->holeIterator = a_holes.insert(a_holes.begin(), instance);
1015 instance->flags |= Flag::HasHole;
1016 instance->flags |= Flag::Ready;
1019 case Mode::TimeWait:
1020 instance->holeIterator = a_holes.insert(a_holes.end(), instance);
1021 instance->flags |= Flag::HasHole;
1022 instance->flags &= Flag::NoReady;
1028 string msg("dbos::StorageArea::Holes::insert | This: ");
1029 msg += functions::asHexString(anna_ptrnumber_cast(this));
1031 msg += StorageArea::asString(instance);
1032 Logger::write(Logger::Local6, msg, ANNA_FILE_LOCATION);
1037 void StorageArea::Holes::erase(Instance* instance)
1039 // instance->msHoleTime = 0;
1040 instance->flags |= Flag::Ready;
1042 if(instance->copyCounter != 0)
1045 /* Si la instancia NO ha sido registrada en la lista de huecos, sale sin más */
1046 if((instance->flags & Flag::HasHole) == false)
1050 string msg("dbos::StorageArea::Holes::erase | This: ");
1051 msg += functions::asHexString(anna_ptrnumber_cast(this));
1053 msg += StorageArea::asString(instance);
1054 Logger::write(Logger::Local6, msg, ANNA_FILE_LOCATION);
1056 a_holes.erase(instance->holeIterator);
1057 instance->flags &= Flag::NoHasHole;
1061 /****************************************************************************************
1066 A () : a (0) { cout << "C0: " << (int) this << endl; }
1067 A (const int _a): a (_a) { cout << "C1: " << (int) this << " " << a << endl; }
1068 A (const A& other) : a (other.a) { cout << "C2: " << (int) this << " " << a << endl; }
1070 A& operator = (const A& other) {
1071 cout << "CP: " << (int) this << " " << (a = other.a) << endl;
1075 int get () const { return a; }
1080 A fx () { return A (2000); }
1089 cout << "CC: " << (int) &cc << " " << cc.get () << endl;
1093 La salida del programucho es la siguiente:
1101 Lo que quiere decir que la "cc" la crea directamente sobre la pila y la asigna en fx sin aplicar ningn
1104 Por eso cuando hac� StorageArea::Iterator ii = xxx->begin (), maxi = xxx->end (); .....
1105 no estaba pasando por el contructor copia ni por ningn otro constructor.
1107 ****************************************************************************************/
1108 // Dejo todo el ejemplo para que sirva de recordatorio.