077da2afc3986531f481e0b87fc7d6c047d169f6
[anna.git] / include / anna / dbos / StorageArea.hpp
1 // ANNA - Anna is Not Nothingness Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // http://redmine.teslayout.com/projects/anna-suite
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
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
16 // distribution.
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.
20 //
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.
32 //
33 // Authors: eduardo.ramos.testillano@gmail.com
34 //          cisco.tierra@gmail.com
35
36
37 #ifndef anna_dbos_StorageArea_hpp
38 #define anna_dbos_StorageArea_hpp
39
40 #include <vector>
41 #include <map>
42 #include <list>
43 #include <deque>
44
45 #include <algorithm>
46
47 #include <anna/core/mt/Mutex.hpp>
48 #include <anna/config/defines.hpp>
49 #include <anna/core/util/SortedVector.hpp>
50
51 #include <anna/dbms/DatabaseException.hpp>
52
53 #include <anna/dbos/defines.hpp>
54 #include <anna/dbos/ObjectAllocator.hpp>
55
56 namespace anna {
57
58 namespace xml {
59 class Node;
60 }
61
62 namespace dbms {
63 class Connection;
64 }
65
66 namespace dbos {
67
68 class Accesor;
69 class Object;
70 class Creator;
71 class Loader;
72 class Recorder;
73 class Eraser;
74 class Repository;
75 class CrossedLoader;
76
77 /**
78    Area de almacenamiento de los objetos obtenidos a partir de los datos guardados en un medio
79    fisico, que normalmente seria una base de datos.
80
81    La creacion de cualquier área de almacenamiento debe hacerse mediante el método
82    anna::dbos::Repository::createStorageArea.
83
84    \warning Exclusivamente para uso interno de anna.dbos
85 */
86 class StorageArea : public Mutex {
87   struct Instance;
88   class Block;
89   class Holes;
90
91 public:
92   /**
93      Modo de acceso al área de almacenamiento.
94   */
95   struct AccessMode {
96     enum _v {
97       /**
98          Carga el objeto una vez y no lo vuelve a comprobar mientras tena un estado valido.
99          No permite la creacion de nuevos objetos.
100       */
101       ReadOnly,
102       /**
103          Carga el objeto una vez e intenta recargarlo cada vez que su cuenta de utilizacion
104          sea cero. Se invocara al método dbos::Object::needUpdate () que se ejecuta antes de
105          realizar ninguna operacion sobre el medio fisico, si devuelve 'true' cargaria la
106          informacion mediante el dbos::Loader correspondiente y se invocaria al
107          método dbos::Object::hasChange (dbos::Loader&).
108       */
109       ReadWrite,
110       /**
111          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
112          realizar ninguna operacion sobre el medio fisico, si devuelve 'true' cargaria la
113          informacion mediante el dbos::Loader correspondiente y se invocaria al
114          método dbos::Object::hasChange (dbos::Loader&).
115       */
116       ReadEver
117     };
118
119     /*
120        Devuelve el literal correspondiente al codigo recibido.
121        \param v Codigo a traducir a literal.
122        \return el literal correspondiente al codigo recibido.
123     */
124     static const char* asString(const _v v) throw();
125   };
126
127   /**
128      Flags usados para marcar los registros cargados en memoria.
129      \warning Exclusivamente uso interno.
130   */
131   struct Flag {
132     enum _v {
133       None = 0, Dirty = 1, Incoherent = 2, Empty = 4, HasHole = 8, Ready = 16, InProgress = 32,
134       NoDirty = ~Dirty, NoIncoherent = ~Incoherent, NoEmpty = ~Empty, NoHasHole = ~HasHole, NoReady = ~Ready, Done = ~InProgress
135     };
136   };
137
138   /**
139      Tamaños normalizados del área de almacenamiento.
140
141      @see StorageArea
142   */
143   struct StandardSize {
144     enum Value {
145       Tiny = 16, /**< Intenta que el número de registros cargados no supere los 16 registros. */
146       Little = 64, /**< Intenta que el número de registros cargados no supere los 64 registros. */
147       Small = 256, /**<Intenta que el número de registros cargados no supere los 256 registros.*/
148       Medium = 2048, /**<Intenta que el número de registros cargados no supere los 2048 registros.*/
149       Large = 8192, /**<Intenta que el número de registros cargados no supere los 8192 registros.*/
150       Huge = 32768, /**<Intenta que el número de registros cargados no supere los 32768 registros.*/
151       LargeHuge = 65536, /**<Intenta que el número de registros cargados no supere los  65536 registros.*/
152       Biggest = 131072 /**<Intenta que el número de registros cargados no supere los 131072 registros.*/
153     };
154   };
155
156   /**
157      Valor que hay que indicar al crear el área de almacenamiento (ver anna::dbos::Repository::createStorageArea)
158      para que el método #instance no devuelva excepcion de ejecucion en caso de no encontrar el
159      registro buscado.
160   */
161   static const int NoExceptionWhenNotFound = -1;
162
163   typedef std::vector <Block*> Blocks; /**< Estructura para mantener los bloques de objetos */
164   typedef std::map <Index, Instance*>::iterator iterator; /**< Definicion para recorrer los objetos del área de almacenamiento */
165   typedef std::map <Index, Instance*>::const_iterator const_iterator; /**< Definicion para recorrer los objetos del área de almacenamiento */
166
167   /**
168      Destructor.
169   */
170   virtual ~StorageArea();
171
172   /**
173    * Devuelve el código de error asociado a la excepción cuando no se encuentra un registro buscado.
174    * \return el código de error asociado a la excepción cuando no se encuentra un registro buscado.
175    */
176   int getErrorCode() const throw() { return a_errorCode; }
177
178   /*
179    * Devuelve el nombre de la este área de almacenamiento.
180    * \return el nombre de la este área de almacenamiento.
181    */
182   const std::string& getName() const throw() { return a_name; }
183
184   /**
185      Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a
186      una clase C++.
187
188      Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
189      debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
190      en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
191      otra combinacion de columnas que lo identifiquen univocamente.
192
193      \param connection Conexion usada si fuera necesario extraer los datos del medio fisico.
194      \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto
195      que deseamos cargar en memoria.
196
197      \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de
198      que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro
199      caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion.
200
201      \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
202      cuando dejemos de usar la instancia.
203   */
204   Object* instance(dbms::Connection& connection, Loader& loader) throw(RuntimeException, dbms::DatabaseException) {
205     return instance(&connection, loader);
206   }
207
208   /**
209      Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a
210      una clase C++.
211
212      Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
213      debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
214      en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
215      otra combinacion de columnas que lo identifiquen univocamente.
216
217      \param connection Conexion usada si fuera necesario extraer los datos del medio fisico.
218      \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto
219      que deseamos cargar en memoria.
220
221      \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de
222      que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro
223      caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion.
224
225      \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
226      cuando dejemos de usar la instancia.
227   */
228   Object* instance(dbms::Connection* connection, Loader& loader) throw(RuntimeException, dbms::DatabaseException);
229
230   /**
231      Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a
232      una clase C++.
233
234      Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
235      debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
236      en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
237      otra combinacion de columnas que lo identifiquen univocamente.
238
239      \param connection Conexion usada si fuera necesario extraer los datos del medio fisico.
240      \param  crossedLoader Cargador encargado de encontrar la clave principal a aplicar con el #Loader
241      recibido como parámetro en base a una clave alternativa contenida en el mismo.
242      \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto
243      que deseamos cargar en memoria.
244
245      \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de
246      que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro
247      caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion.
248
249      \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
250      cuando dejemos de usar la instancia.
251   */
252   Object* instance(dbms::Connection& connection, CrossedLoader& crossedLoader,  Loader& loader)
253   throw(RuntimeException, dbms::DatabaseException) {
254     return instance(&connection, crossedLoader, loader);
255   }
256
257   /**
258      Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a
259      una clase C++.
260
261      Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
262      debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
263      en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
264      otra combinacion de columnas que lo identifiquen univocamente.
265
266      \param connection Conexion usada si fuera necesario extraer los datos del medio fisico.
267      \param  crossedLoader Cargador encargado de encontrar la clave principal a aplicar con el #Loader
268      recibido como parámetro en base a una clave alternativa contenida en el mismo.
269      \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto
270      que deseamos cargar en memoria.
271
272      \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de
273      que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro
274      caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion.
275
276      \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
277      cuando dejemos de usar la instancia.
278   */
279   Object* instance(dbms::Connection* connection, CrossedLoader& crossedLoader,  Loader& loader)
280   throw(RuntimeException, dbms::DatabaseException);
281
282   /**
283      Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a
284      una clase C++.
285
286      Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
287      debe cargar.
288
289      \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto
290      que deseamos cargar en memoria.
291
292      \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de
293      que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro
294      caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion.
295
296      \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
297      cuando dejemos de usar la instancia.
298      \warning Para usar este método se requiere haber re-escrito el método virtual Loader::load para que no intente
299      obtener los datos desde la base de datos.
300   */
301   Object* instance(Loader& loader) throw(RuntimeException, dbms::DatabaseException) {
302     return instance(NULL, loader);
303   }
304
305   /**
306       Crea un objeto en el área de almacenamiento un y lo prepara para ser transferido al medio fisico
307       si fuera necesario.
308
309       Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
310       debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
311       en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
312       otra combinacion de columnas que lo identifiquen univocamente.
313
314       \param connection Conexion usada si fuera necesario acceder al medio fisico.
315       \param creator Creador encargado de generar el objeto en el área de almacenamiento.
316
317       \return La nueva instancia que cumple el patron establecido por el creador.
318
319       \warning \li Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
320       cuando dejemos de usar la instancia.
321       \li No puede usarse en las áreas de almacenamiento definidas como AccessMode::ReadOnly.
322    */
323   Object* create(dbms::Connection& connection, Creator& creator) throw(RuntimeException, dbms::DatabaseException) {
324     return create(&connection, creator);
325   }
326
327   /**
328       Crea un objeto en el área de almacenamiento un y lo prepara para ser transferido al medio fisico
329       si fuera necesario.
330
331       Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
332       debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
333       en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
334       otra combinacion de columnas que lo identifiquen univocamente.
335
336       \param connection Conexion usada si fuera necesario acceder al medio fisico.
337       \param creator Creador encargado de generar el objeto en el área de almacenamiento.
338
339       \return La nueva instancia que cumple el patron establecido por el creador.
340
341       \warning \li Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
342       cuando dejemos de usar la instancia.
343       \li No puede usarse en las áreas de almacenamiento definidas como AccessMode::ReadOnly.
344    */
345   Object* create(dbms::Connection* connection, Creator& creator) throw(RuntimeException, dbms::DatabaseException);
346
347   /**
348       Crea un objeto en el área de almacenamiento y lo prepara para ser transferido al medio fisico
349       si fuera necesario.
350
351       Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
352       debe cargar.
353
354       \param creator Creador encargado de generar el objeto en el área de almacenamiento.
355
356       \return La nueva instancia que cumple el patron establecido por el creador.
357
358       \warning \li Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
359       cuando dejemos de usar la instancia.
360       \li No puede usarse en las áreas de almacenamiento definidas como AccessMode::ReadOnly.
361    */
362   Object* create(Creator& creator) throw(RuntimeException, dbms::DatabaseException) { return create(NULL, creator); }
363
364   /**
365      Devuelve la informacion de un objeto cargado desde el medio fisico.
366
367      Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
368      debe buscar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
369      en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
370      otra combinacion de columnas que lo identifiquen univocamente.
371
372      \param loader Cargador de clase encargado de localizar la informacion referente al objeto buscado.
373
374      \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL si el
375      objeto no fue cargado en el área de almacenamiento.
376
377      \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
378      cuando dejemos de usar la instancia.
379   */
380   Object* find(Loader& loader) throw(RuntimeException);
381
382   /**
383      Devuelve de una copia del objeto recibido como parámetro e incrementa la cuenta de utilizacion
384      asociada a la instancia.
385
386      \param object Instancia obtenida mediate el método #instance.
387
388      \return Una copia del objeto recibido como parámetro. Si el parámetro recibido es NULL devolveria NULL.
389
390      \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
391      cuando dejemos de usar la instancia.
392   */
393   Object* duplicate(const Object* object) throw(RuntimeException);
394
395   /**
396      Permite conocer si un determinado objeto esta alojado en el área de almacenamiento. No
397      cambia la cuenta de utilizacion de los objetos ni provoca cambios en las estadisticas
398      de aciertos.
399
400      \param loader Cargador de clase encargado de localizar la informacion referente al objeto buscado.
401
402      \return \em true Si el objeto identificado por el Loader esta en el área de almacenamiento o
403      \em false en otro caso.
404   */
405   bool isLoaded(const Loader& loader) throw(RuntimeException);
406
407   /**
408      Transfiere la informacion del objeto recibido como parámetro al medio fisico usando el Recorder
409      recibido como parámetro.
410
411      \param connection Conexion usada si fuera necesario acceder al medio fisico.
412      \param recorder Grabador usado para transferir los datos al medio fisico.
413   */
414   void apply(dbms::Connection& connection, Recorder& recorder) throw(RuntimeException, dbms::DatabaseException);
415
416   /**
417      Elimina la informacion del objeto recibido como parámetro del medio fisico usando el Eraser
418      recibido como parámetro.
419
420      \param connection Conexion usada si fuera necesario acceder al medio fisico.
421      \param eraser Objecto usado para eliminar los datos al medio fisico.
422
423      \warning Si la cuenta de utilizacion del objeto es 1 se liberaría en otro caso se devolvería una excepción.
424   */
425   void apply(dbms::Connection& connection, Eraser& eraser) throw(RuntimeException, dbms::DatabaseException);
426
427   /**
428      Habilita la reutilizacion del espacio de memoria ocupado por un objeto instanciado mediate #instance.
429
430      Este método no saca al objeto de la memoria de almacenamiento, sino que marca su espacio de memoria
431      como subceptible de ser reutilizado. De esta forma, si el número de objetos cargados en memoria se
432      acerca al tamaño maximo indicado en la inicializacin, cuando halla que cargar un nuevo registro se
433      reusaria el espacio libre en vez de seguir aumentando el tamaño de la memoria de almacenamiento.
434
435      \param object Instancia del objeto que vamos a liberar.
436
437      \warning Si el objeto recibido como parámetro no fue reservado mediate #instance no tiene
438      ningun efecto.
439   */
440   void release(Object** object) throw(RuntimeException);
441
442   /**
443      Elimina toda la informacion referente al objeto recibido como parámetro, siempre y cuando
444      solo tenga un unica referencia activa. Descarga el objeto de la memoria de almacenamiento,
445
446      \param object Instancia que vamos a descargar de la memoria de almacenamiento.
447
448      \warning \li Si el objeto recibido como parámetro no fue reservado mediate #instance no tiene
449      ningun efecto.
450      \li La instancia a liberar solo puede tener 1 en su cuenta de utilizacion.
451   */
452   void erase(Object** object) throw(RuntimeException);
453
454   /**
455      Marca el objeto recibido como pendiente de recarga de datos.
456
457      \param object Instancia que vamos a marcar como pendiente de recarga.
458
459      \warning \li Si el objeto recibido como parámetro no fue reservado mediate #instance no tiene
460      ningun efecto.
461      \li La instancia a marcar solo deberia tener una unica instancia en uso.
462   */
463   void dirty(Object* object) throw(RuntimeException);
464
465   /**
466      Establece el tamanho de las instancias de los objetos contenidos en este área de almacenamiento.
467      \param _sizeof Numero de bytes ocupado por cada una de las instancias.
468   */
469   void setSizeof(const Size _sizeof) throw() { a_sizeof = _sizeof + sizeof(Instance); }
470
471   /**
472      Devuelve el numero maximo de bytes teorico que puede llegar a reservar este área de almacenamiento.
473      \return el numero maximo de bytes teorico que puede llegar a reservar este área de almacenamiento.
474   */
475   Size getMaxSizeOf() const throw() { return a_maxSize * a_sizeof; }
476
477   /**
478      Devuelve el numero de bytes teorico que puede llegar a reservar este área de almacenamiento.
479      \return el numero de bytes teorico que puede llegar a reservar este área de almacenamiento.
480   */
481   Size getSizeOf() const throw() { return a_directory.size() * a_sizeof; }
482
483   /**
484      Devuelve un iterator al primero de los objetos contenido en el área del almacenamiento.
485      \return Un iterator al primero de los objetos contenido en el área del almacenamiento.
486   */
487   iterator begin() throw() { return a_directory.begin(); }
488
489   /**
490      Devuelve un iterator al primero de los objetos contenido en el área del almacenamiento.
491      \return Un iterator al primero de los objetos contenido en el área del almacenamiento.
492   */
493   const_iterator begin() const throw() { return a_directory.begin(); }
494
495   /**
496      Devuelve un iterator al fin de los objetos contenidos en el área del almacenamiento.
497      \return Un iterator al fin de los objetos contenidos en el área del almacenamiento.
498   */
499   iterator end() throw() { return a_directory.end(); }
500
501   /**
502      Devuelve un iterator al fin de los objetos contenidos en el área del almacenamiento.
503      \return Un iterator al fin de los objetos contenidos en el área del almacenamiento.
504   */
505   const_iterator end() const throw() { return a_directory.end(); }
506
507   /**
508      Devuelve el puntero sobre el que esta posicionado el iterador recibido como parámetro.
509      \return El puntero sobre el que esta posicionado el iterador recibido como parámetro.
510   */
511   static Object* data(iterator ii) throw() { return ii->second->object; }
512
513   /**
514      Devuelve el puntero sobre el que esta posicionado el iterador recibido como parámetro.
515      \return El puntero sobre el que esta posicionado el iterador recibido como parámetro.
516   */
517   static const Object* data(const_iterator ii) throw() { return ii->second->object; }
518
519   /**
520      Devuelve una cadena con la informacion referente a este área de almacenamiento.
521      \return Una cadena con la informacion referente a este área de almacenamiento.
522   */
523   std::string asString() const throw();
524
525   /**
526      Devuelve un documento XML con la informacion referente a esta instancia.
527      \param parent Nodo XML del que dependende la informacion.
528      @return un documento XML con la informacion referente a esta instancia.
529   */
530   xml::Node* asXML(xml::Node* parent) const throw();
531
532 protected:
533   /**
534      Descarga del área de almacenamiento todos los objetos que estuviera cargados.
535      Este método se invoca desde anna::dbos::Repository::clear
536   */
537   void clear() throw(RuntimeException);
538
539   /**
540      Devuelve un literal con el entero recibido tratado como una cantidad en bytes.
541      \return un literal con el entero recibido tratado como un cantidad en bytes
542   */
543   static std::string asMemorySize(const Size size) throw();
544
545 private:
546   typedef std::map <Index, Instance*>::value_type value_type;
547
548   struct Instance;
549
550   friend class Holes;
551
552   class Holes {
553   public:
554     struct Mode { enum _v { ReadyToReuse, TimeWait }; };
555
556     typedef std::list <Instance*> hole_container;
557     typedef hole_container::iterator hole_iterator;
558
559     Holes() : a_size(0) {;}
560
561     bool insert(Instance* instance, const Mode::_v mode) throw();
562     void erase(Instance* instance) throw();
563     Instance* front() throw() { return a_holes.front(); }
564     int size() const throw() { return a_size; }
565     int empty() const throw() { return a_holes.empty(); }
566     void pop_front() throw() { a_holes.pop_front(); a_size --; }
567     void clear() throw() { a_holes.clear(); a_size = 0; }
568
569   private:
570     hole_container a_holes;
571     int a_size;
572   };
573
574   //------------------------------------------------------------------------
575   // - object: Puntero a la instancia con el objeto cacheado.
576   // - msHoleTime: Millisecond en el que entra en la lista de huecos.
577   // - copyCounter: Numero de copias del objeto.
578   // - flags: Flags (Dirty, Incoherent, Empty).
579   //------------------------------------------------------------------------
580   friend struct Instance;
581
582   struct Instance {
583     Object* object;
584     Counter copyCounter;
585     int flags;
586     Holes::hole_iterator holeIterator;
587
588     Instance() : copyCounter(0), object(NULL), flags(Flag::None) {;}
589   };
590
591   friend class Block;
592
593   class Block {
594   public:
595     Block(ObjectAllocator objectAllocator, const Size maxSize);
596     Instance* getInstance() throw() { return (a_size < a_maxSize) ? &a_instances [a_size ++] : NULL; }
597     void reset() throw() { a_size = 0; }
598
599   private:
600     Instance* a_instances;
601     Size a_maxSize;
602     Size a_size;
603   };
604
605   const std::string a_name;
606   const Size a_maxSize;
607   ObjectAllocator a_objectAllocator;
608   const AccessMode::_v a_accessMode;
609   int a_errorCode;
610   Size a_sizeof;
611
612   Blocks a_blocks;
613   std::map <Index, Instance*> a_directory;
614   Holes a_holes;
615   Block* a_currentBlock;
616   int a_indexBlock;
617   Counter a_hit;
618   Counter a_fault;
619   Counter a_doneReuse;
620
621   /*
622      typedef std::deque <std::pair <DBIndex> inprogress_container;
623      typedef inprogress_container::iterator inprogress_iterator;
624      inprogress_container a_inprogress;
625
626      inprogress_iterator inprogress_begin () const throw () { return a_inprogress.begin (); }
627      inprogress_iterator inprogress_end () const throw () { return a_inprogress.end (); }
628      static DBIndex index (inprogress_iterator ii) throw () { return *ii; }
629      bool isInProgress (const DBIndex index) const throw ();
630   */
631
632   /*
633    * Constructor.
634    * \warning Este método sólo debería usarse desde el método dbos::Repository::allocateStorageArea.
635    */
636   StorageArea(const char* name, const Size maxSize, ObjectAllocator, const AccessMode::_v, const int errorCode);
637   StorageArea(const StorageArea&);
638
639   Object* reload(dbms::Connection*, Loader&, Instance*) throw(RuntimeException, dbms::DatabaseException);
640   void checkIncoherence(Instance*) throw();
641   bool quickReusing(Instance*) throw();
642   void verifyStatus(StorageArea::Instance*, const bool ignoreDirty = false) throw(RuntimeException);
643   Instance* allocate() throw();
644   Instance* reuse() throw();
645
646   static Instance* instance(iterator& ii) throw() { return ii->second; }
647   static std::string asString(const Instance*) throw();
648
649   friend class Repository;
650 };
651
652 }
653 }
654
655 #endif