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 //
9 #ifndef anna_dbos_StorageArea_hpp
10 #define anna_dbos_StorageArea_hpp
19 #include <anna/core/mt/Mutex.hpp>
20 #include <anna/config/defines.hpp>
21 #include <anna/core/util/SortedVector.hpp>
23 #include <anna/dbms/DatabaseException.hpp>
25 #include <anna/dbos/defines.hpp>
26 #include <anna/dbos/ObjectAllocator.hpp>
50 Area de almacenamiento de los objetos obtenidos a partir de los datos guardados en un medio
51 fisico, que normalmente seria una base de datos.
53 La creacion de cualquier área de almacenamiento debe hacerse mediante el método
54 anna::dbos::Repository::createStorageArea.
56 \warning Exclusivamente para uso interno de anna.dbos
58 class StorageArea : public Mutex {
65 Modo de acceso al área de almacenamiento.
70 Carga el objeto una vez y no lo vuelve a comprobar mientras tena un estado valido.
71 No permite la creacion de nuevos objetos.
75 Carga el objeto una vez e intenta recargarlo cada vez que su cuenta de utilizacion
76 sea cero. Se invocara al método dbos::Object::needUpdate () que se ejecuta antes de
77 realizar ninguna operacion sobre el medio fisico, si devuelve 'true' cargaria la
78 informacion mediante el dbos::Loader correspondiente y se invocaria al
79 método dbos::Object::hasChange (dbos::Loader&).
83 Comprueba la recarga del objeto cada vez que se accede a el. Se invocara al método dbos::Object::needUpdate () que se ejecuta antes de
84 realizar ninguna operacion sobre el medio fisico, si devuelve 'true' cargaria la
85 informacion mediante el dbos::Loader correspondiente y se invocaria al
86 método dbos::Object::hasChange (dbos::Loader&).
92 Devuelve el literal correspondiente al codigo recibido.
93 \param v Codigo a traducir a literal.
94 \return el literal correspondiente al codigo recibido.
96 static const char* asString(const _v v) throw();
100 Flags usados para marcar los registros cargados en memoria.
101 \warning Exclusivamente uso interno.
105 None = 0, Dirty = 1, Incoherent = 2, Empty = 4, HasHole = 8, Ready = 16, InProgress = 32,
106 NoDirty = ~Dirty, NoIncoherent = ~Incoherent, NoEmpty = ~Empty, NoHasHole = ~HasHole, NoReady = ~Ready, Done = ~InProgress
111 Tamaños normalizados del área de almacenamiento.
115 struct StandardSize {
117 Tiny = 16, /**< Intenta que el número de registros cargados no supere los 16 registros. */
118 Little = 64, /**< Intenta que el número de registros cargados no supere los 64 registros. */
119 Small = 256, /**<Intenta que el número de registros cargados no supere los 256 registros.*/
120 Medium = 2048, /**<Intenta que el número de registros cargados no supere los 2048 registros.*/
121 Large = 8192, /**<Intenta que el número de registros cargados no supere los 8192 registros.*/
122 Huge = 32768, /**<Intenta que el número de registros cargados no supere los 32768 registros.*/
123 LargeHuge = 65536, /**<Intenta que el número de registros cargados no supere los 65536 registros.*/
124 Biggest = 131072 /**<Intenta que el número de registros cargados no supere los 131072 registros.*/
129 Valor que hay que indicar al crear el área de almacenamiento (ver anna::dbos::Repository::createStorageArea)
130 para que el método #instance no devuelva excepcion de ejecucion en caso de no encontrar el
133 static const int NoExceptionWhenNotFound = -1;
135 typedef std::vector <Block*> Blocks; /**< Estructura para mantener los bloques de objetos */
136 typedef std::map <Index, Instance*>::iterator iterator; /**< Definicion para recorrer los objetos del área de almacenamiento */
137 typedef std::map <Index, Instance*>::const_iterator const_iterator; /**< Definicion para recorrer los objetos del área de almacenamiento */
142 virtual ~StorageArea();
145 * Devuelve el código de error asociado a la excepción cuando no se encuentra un registro buscado.
146 * \return el código de error asociado a la excepción cuando no se encuentra un registro buscado.
148 int getErrorCode() const throw() { return a_errorCode; }
151 * Devuelve el nombre de la este área de almacenamiento.
152 * \return el nombre de la este área de almacenamiento.
154 const std::string& getName() const throw() { return a_name; }
157 Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a
160 Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
161 debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
162 en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
163 otra combinacion de columnas que lo identifiquen univocamente.
165 \param connection Conexion usada si fuera necesario extraer los datos del medio fisico.
166 \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto
167 que deseamos cargar en memoria.
169 \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de
170 que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro
171 caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion.
173 \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
174 cuando dejemos de usar la instancia.
176 Object* instance(dbms::Connection& connection, Loader& loader) throw(RuntimeException, dbms::DatabaseException) {
177 return instance(&connection, loader);
181 Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a
184 Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
185 debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
186 en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
187 otra combinacion de columnas que lo identifiquen univocamente.
189 \param connection Conexion usada si fuera necesario extraer los datos del medio fisico.
190 \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto
191 que deseamos cargar en memoria.
193 \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de
194 que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro
195 caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion.
197 \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
198 cuando dejemos de usar la instancia.
200 Object* instance(dbms::Connection* connection, Loader& loader) throw(RuntimeException, dbms::DatabaseException);
203 Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a
206 Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
207 debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
208 en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
209 otra combinacion de columnas que lo identifiquen univocamente.
211 \param connection Conexion usada si fuera necesario extraer los datos del medio fisico.
212 \param crossedLoader Cargador encargado de encontrar la clave principal a aplicar con el #Loader
213 recibido como parámetro en base a una clave alternativa contenida en el mismo.
214 \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto
215 que deseamos cargar en memoria.
217 \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de
218 que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro
219 caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion.
221 \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
222 cuando dejemos de usar la instancia.
224 Object* instance(dbms::Connection& connection, CrossedLoader& crossedLoader, Loader& loader)
225 throw(RuntimeException, dbms::DatabaseException) {
226 return instance(&connection, crossedLoader, loader);
230 Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a
233 Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
234 debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
235 en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
236 otra combinacion de columnas que lo identifiquen univocamente.
238 \param connection Conexion usada si fuera necesario extraer los datos del medio fisico.
239 \param crossedLoader Cargador encargado de encontrar la clave principal a aplicar con el #Loader
240 recibido como parámetro en base a una clave alternativa contenida en el mismo.
241 \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto
242 que deseamos cargar en memoria.
244 \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de
245 que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro
246 caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion.
248 \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
249 cuando dejemos de usar la instancia.
251 Object* instance(dbms::Connection* connection, CrossedLoader& crossedLoader, Loader& loader)
252 throw(RuntimeException, dbms::DatabaseException);
255 Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a
258 Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
261 \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto
262 que deseamos cargar en memoria.
264 \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de
265 que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro
266 caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion.
268 \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
269 cuando dejemos de usar la instancia.
270 \warning Para usar este método se requiere haber re-escrito el método virtual Loader::load para que no intente
271 obtener los datos desde la base de datos.
273 Object* instance(Loader& loader) throw(RuntimeException, dbms::DatabaseException) {
274 return instance(NULL, loader);
278 Crea un objeto en el área de almacenamiento un y lo prepara para ser transferido al medio fisico
281 Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
282 debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
283 en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
284 otra combinacion de columnas que lo identifiquen univocamente.
286 \param connection Conexion usada si fuera necesario acceder al medio fisico.
287 \param creator Creador encargado de generar el objeto en el área de almacenamiento.
289 \return La nueva instancia que cumple el patron establecido por el creador.
291 \warning \li Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
292 cuando dejemos de usar la instancia.
293 \li No puede usarse en las áreas de almacenamiento definidas como AccessMode::ReadOnly.
295 Object* create(dbms::Connection& connection, Creator& creator) throw(RuntimeException, dbms::DatabaseException) {
296 return create(&connection, creator);
300 Crea un objeto en el área de almacenamiento un y lo prepara para ser transferido al medio fisico
303 Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
304 debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
305 en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
306 otra combinacion de columnas que lo identifiquen univocamente.
308 \param connection Conexion usada si fuera necesario acceder al medio fisico.
309 \param creator Creador encargado de generar el objeto en el área de almacenamiento.
311 \return La nueva instancia que cumple el patron establecido por el creador.
313 \warning \li Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
314 cuando dejemos de usar la instancia.
315 \li No puede usarse en las áreas de almacenamiento definidas como AccessMode::ReadOnly.
317 Object* create(dbms::Connection* connection, Creator& creator) throw(RuntimeException, dbms::DatabaseException);
320 Crea un objeto en el área de almacenamiento y lo prepara para ser transferido al medio fisico
323 Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
326 \param creator Creador encargado de generar el objeto en el área de almacenamiento.
328 \return La nueva instancia que cumple el patron establecido por el creador.
330 \warning \li Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
331 cuando dejemos de usar la instancia.
332 \li No puede usarse en las áreas de almacenamiento definidas como AccessMode::ReadOnly.
334 Object* create(Creator& creator) throw(RuntimeException, dbms::DatabaseException) { return create(NULL, creator); }
337 Devuelve la informacion de un objeto cargado desde el medio fisico.
339 Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
340 debe buscar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
341 en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
342 otra combinacion de columnas que lo identifiquen univocamente.
344 \param loader Cargador de clase encargado de localizar la informacion referente al objeto buscado.
346 \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL si el
347 objeto no fue cargado en el área de almacenamiento.
349 \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
350 cuando dejemos de usar la instancia.
352 Object* find(Loader& loader) throw(RuntimeException);
355 Devuelve de una copia del objeto recibido como parámetro e incrementa la cuenta de utilizacion
356 asociada a la instancia.
358 \param object Instancia obtenida mediate el método #instance.
360 \return Una copia del objeto recibido como parámetro. Si el parámetro recibido es NULL devolveria NULL.
362 \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
363 cuando dejemos de usar la instancia.
365 Object* duplicate(const Object* object) throw(RuntimeException);
368 Permite conocer si un determinado objeto esta alojado en el área de almacenamiento. No
369 cambia la cuenta de utilizacion de los objetos ni provoca cambios en las estadisticas
372 \param loader Cargador de clase encargado de localizar la informacion referente al objeto buscado.
374 \return \em true Si el objeto identificado por el Loader esta en el área de almacenamiento o
375 \em false en otro caso.
377 bool isLoaded(const Loader& loader) throw(RuntimeException);
380 Transfiere la informacion del objeto recibido como parámetro al medio fisico usando el Recorder
381 recibido como parámetro.
383 \param connection Conexion usada si fuera necesario acceder al medio fisico.
384 \param recorder Grabador usado para transferir los datos al medio fisico.
386 void apply(dbms::Connection& connection, Recorder& recorder) throw(RuntimeException, dbms::DatabaseException);
389 Elimina la informacion del objeto recibido como parámetro del medio fisico usando el Eraser
390 recibido como parámetro.
392 \param connection Conexion usada si fuera necesario acceder al medio fisico.
393 \param eraser Objecto usado para eliminar los datos al medio fisico.
395 \warning Si la cuenta de utilizacion del objeto es 1 se liberaría en otro caso se devolvería una excepción.
397 void apply(dbms::Connection& connection, Eraser& eraser) throw(RuntimeException, dbms::DatabaseException);
400 Habilita la reutilizacion del espacio de memoria ocupado por un objeto instanciado mediate #instance.
402 Este método no saca al objeto de la memoria de almacenamiento, sino que marca su espacio de memoria
403 como subceptible de ser reutilizado. De esta forma, si el número de objetos cargados en memoria se
404 acerca al tamaño maximo indicado en la inicializacin, cuando halla que cargar un nuevo registro se
405 reusaria el espacio libre en vez de seguir aumentando el tamaño de la memoria de almacenamiento.
407 \param object Instancia del objeto que vamos a liberar.
409 \warning Si el objeto recibido como parámetro no fue reservado mediate #instance no tiene
412 void release(Object** object) throw(RuntimeException);
415 Elimina toda la informacion referente al objeto recibido como parámetro, siempre y cuando
416 solo tenga un unica referencia activa. Descarga el objeto de la memoria de almacenamiento,
418 \param object Instancia que vamos a descargar de la memoria de almacenamiento.
420 \warning \li Si el objeto recibido como parámetro no fue reservado mediate #instance no tiene
422 \li La instancia a liberar solo puede tener 1 en su cuenta de utilizacion.
424 void erase(Object** object) throw(RuntimeException);
427 Marca el objeto recibido como pendiente de recarga de datos.
429 \param object Instancia que vamos a marcar como pendiente de recarga.
431 \warning \li Si el objeto recibido como parámetro no fue reservado mediate #instance no tiene
433 \li La instancia a marcar solo deberia tener una unica instancia en uso.
435 void dirty(Object* object) throw(RuntimeException);
438 Establece el tamanho de las instancias de los objetos contenidos en este área de almacenamiento.
439 \param _sizeof Numero de bytes ocupado por cada una de las instancias.
441 void setSizeof(const Size _sizeof) throw() { a_sizeof = _sizeof + sizeof(Instance); }
444 Devuelve el numero maximo de bytes teorico que puede llegar a reservar este área de almacenamiento.
445 \return el numero maximo de bytes teorico que puede llegar a reservar este área de almacenamiento.
447 Size getMaxSizeOf() const throw() { return a_maxSize * a_sizeof; }
450 Devuelve el numero de bytes teorico que puede llegar a reservar este área de almacenamiento.
451 \return el numero de bytes teorico que puede llegar a reservar este área de almacenamiento.
453 Size getSizeOf() const throw() { return a_directory.size() * a_sizeof; }
456 Devuelve un iterator al primero de los objetos contenido en el área del almacenamiento.
457 \return Un iterator al primero de los objetos contenido en el área del almacenamiento.
459 iterator begin() throw() { return a_directory.begin(); }
462 Devuelve un iterator al primero de los objetos contenido en el área del almacenamiento.
463 \return Un iterator al primero de los objetos contenido en el área del almacenamiento.
465 const_iterator begin() const throw() { return a_directory.begin(); }
468 Devuelve un iterator al fin de los objetos contenidos en el área del almacenamiento.
469 \return Un iterator al fin de los objetos contenidos en el área del almacenamiento.
471 iterator end() throw() { return a_directory.end(); }
474 Devuelve un iterator al fin de los objetos contenidos en el área del almacenamiento.
475 \return Un iterator al fin de los objetos contenidos en el área del almacenamiento.
477 const_iterator end() const throw() { return a_directory.end(); }
480 Devuelve el puntero sobre el que esta posicionado el iterador recibido como parámetro.
481 \return El puntero sobre el que esta posicionado el iterador recibido como parámetro.
483 static Object* data(iterator ii) throw() { return ii->second->object; }
486 Devuelve el puntero sobre el que esta posicionado el iterador recibido como parámetro.
487 \return El puntero sobre el que esta posicionado el iterador recibido como parámetro.
489 static const Object* data(const_iterator ii) throw() { return ii->second->object; }
492 Devuelve una cadena con la informacion referente a este área de almacenamiento.
493 \return Una cadena con la informacion referente a este área de almacenamiento.
495 std::string asString() const throw();
498 Devuelve un documento XML con la informacion referente a esta instancia.
499 \param parent Nodo XML del que dependende la informacion.
500 @return un documento XML con la informacion referente a esta instancia.
502 xml::Node* asXML(xml::Node* parent) const throw();
506 Descarga del área de almacenamiento todos los objetos que estuviera cargados.
507 Este método se invoca desde anna::dbos::Repository::clear
509 void clear() throw(RuntimeException);
512 Devuelve un literal con el entero recibido tratado como una cantidad en bytes.
513 \return un literal con el entero recibido tratado como un cantidad en bytes
515 static std::string asMemorySize(const Size size) throw();
518 typedef std::map <Index, Instance*>::value_type value_type;
524 struct Mode { enum _v { ReadyToReuse, TimeWait }; };
526 typedef std::list <Instance*> hole_container;
527 typedef hole_container::iterator hole_iterator;
529 Holes() : a_size(0) {;}
531 bool insert(Instance* instance, const Mode::_v mode) throw();
532 void erase(Instance* instance) throw();
533 Instance* front() throw() { return a_holes.front(); }
534 int size() const throw() { return a_size; }
535 int empty() const throw() { return a_holes.empty(); }
536 void pop_front() throw() { a_holes.pop_front(); a_size --; }
537 void clear() throw() { a_holes.clear(); a_size = 0; }
540 hole_container a_holes;
544 //------------------------------------------------------------------------
545 // - object: Puntero a la instancia con el objeto cacheado.
546 // - msHoleTime: Millisecond en el que entra en la lista de huecos.
547 // - copyCounter: Numero de copias del objeto.
548 // - flags: Flags (Dirty, Incoherent, Empty).
549 //------------------------------------------------------------------------
550 friend struct Instance;
556 Holes::hole_iterator holeIterator;
558 Instance() : copyCounter(0), object(NULL), flags(Flag::None) {;}
565 Block(ObjectAllocator objectAllocator, const Size maxSize);
566 Instance* getInstance() throw() { return (a_size < a_maxSize) ? &a_instances [a_size ++] : NULL; }
567 void reset() throw() { a_size = 0; }
570 Instance* a_instances;
575 const std::string a_name;
576 const Size a_maxSize;
577 ObjectAllocator a_objectAllocator;
578 const AccessMode::_v a_accessMode;
583 std::map <Index, Instance*> a_directory;
585 Block* a_currentBlock;
592 typedef std::deque <std::pair <DBIndex> inprogress_container;
593 typedef inprogress_container::iterator inprogress_iterator;
594 inprogress_container a_inprogress;
596 inprogress_iterator inprogress_begin () const throw () { return a_inprogress.begin (); }
597 inprogress_iterator inprogress_end () const throw () { return a_inprogress.end (); }
598 static DBIndex index (inprogress_iterator ii) throw () { return *ii; }
599 bool isInProgress (const DBIndex index) const throw ();
604 * \warning Este método sólo debería usarse desde el método dbos::Repository::allocateStorageArea.
606 StorageArea(const char* name, const Size maxSize, ObjectAllocator, const AccessMode::_v, const int errorCode);
607 StorageArea(const StorageArea&);
609 Object* reload(dbms::Connection*, Loader&, Instance*) throw(RuntimeException, dbms::DatabaseException);
610 void checkIncoherence(Instance*) throw();
611 bool quickReusing(Instance*) throw();
612 void verifyStatus(StorageArea::Instance*, const bool ignoreDirty = false) throw(RuntimeException);
613 Instance* allocate() throw();
614 Instance* reuse() throw();
616 static Instance* instance(iterator& ii) throw() { return ii->second; }
617 static std::string asString(const Instance*) throw();
619 friend class Repository;