Updated license
[anna.git] / example / dbos / workdir / main.cpp
1 // ANNA - Anna is Not Nothingness Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // https://bitbucket.org/testillano/anna
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 Google Inc. 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 #include <iostream>
38
39 #include <anna/core/core.hpp>
40 #include <anna/app/app.hpp>
41
42 #include <anna/io/Directory.hpp>
43 #include <anna/io/functions.hpp>
44
45 #include <anna/xml/Compiler.hpp>
46 #include <anna/xml/Node.hpp>
47
48 #include <anna/dbos/Repository.hpp>
49 #include <anna/dbos/AutoObject.hpp>
50
51 #include "filesystem/Directory.hpp"
52 #include "filesystem/File.hpp"
53
54 #include "storage/Directory.hpp"
55 #include "storage/File.hpp"
56
57 using namespace std;
58 using namespace workdir;
59
60 template <typename T> void message (const char* text, T* tt) throw () {
61    if (Logger::isActive (Logger::Debug) == false)
62       return;
63
64    cout << "   " << text << " (";
65    cout << anna::functions::asHexString (anna_ptrnumber_cast (tt)); 
66    cout << "): ";
67    
68    if (tt != NULL)
69       cout << tt->asString ();
70    else
71       cout << "<null>";
72    
73    cout << endl;
74 }
75
76 class WorkDirectory : public Application {
77 public:
78    struct Flags { enum _v { None = 0, Clear = 1 }; };
79    
80    WorkDirectory ();
81
82    xml::Node* asXML (xml::Node* parent) const throw ();
83    
84 private:
85    typedef vector <storage::File*> file_container;
86    typedef file_container::iterator file_iterator;
87    typedef file_container::reverse_iterator file_reverse_iterator;
88    
89    dbos::Repository a_repository;
90    filesystem::Directory* a_root;
91    file_container a_files;
92
93    void initialize () throw (RuntimeException); 
94    void run () throw (RuntimeException);
95    
96    void forward (filesystem::Directory*) throw (RuntimeException);
97    void instantiateOne (filesystem::Directory*) throw (RuntimeException);   
98    void fullCache (filesystem::Directory*, file_container&, const int flags) throw (RuntimeException);   
99    void reuseHoles (filesystem::Directory*, file_container&) throw (RuntimeException);
100    void destroyObjects (filesystem::Directory* dir, file_container&) throw (RuntimeException);
101    void clear (file_container&) throw ();
102    
103    static void load (filesystem::Directory* parent, const int maxLevel, const int level = 0) throw (RuntimeException);
104 };
105
106 using namespace std;
107
108 int main (int argc, const char** argv)
109 {
110    CommandLine& commandLine (CommandLine::instantiate ());
111    WorkDirectory storageNull;
112
113    try {
114       commandLine.initialize (argv, argc);
115       commandLine.verify ();
116
117       Logger::setLevel (Logger::Local6); 
118       Logger::initialize ("workdir", new TraceWriter ("file.trace", 4 * 1024 * 1024));
119  
120       storageNull.start ();
121    }
122    catch (Exception& ex) {
123       cout << ex.asString () << endl;
124    }
125    
126    return 0;
127 }
128
129 WorkDirectory::WorkDirectory () : 
130    Application ("workdir", "Dbos workdir", "1.0.0"),
131    a_repository ("workdir")
132 {
133    CommandLine& cl (CommandLine::instantiate ());
134       
135    cl.add ("dir", CommandLine::Argument::Mandatory, "Nombre del directorio a procesar");
136    cl.add ("l", CommandLine::Argument::Optional, "Nº máximo de niveles de profundidad");
137    cl.add ("trace", CommandLine::Argument::Optional, "Nivel de trazado");
138    cl.add ("s", CommandLine::Argument::Mandatory, "Cache size");
139 }
140
141 void WorkDirectory::initialize ()
142    throw (RuntimeException)
143 {
144 }
145
146 void WorkDirectory::run () 
147    throw (RuntimeException)
148 {
149    LOGMETHOD (TraceMethod tm ("WorkDirectory", "run", ANNA_FILE_LOCATION)); 
150
151    CommandLine& cl (CommandLine::instantiate ());  
152
153    const std::string& dir = cl.getValue ("dir");
154    const int maxLevel = cl.exists ("l") ? cl.getIntegerValue ("l"): -1; 
155
156    if (cl.exists ("trace") == true) 
157       Logger::setLevel (Logger::asLevel (cl.getValue ("trace")));
158
159    const int cacheSize = cl.getIntegerValue ("s");
160    
161    storage::Directory::setup (a_repository, cacheSize);
162    storage::File::setup (a_repository, cacheSize);
163    
164    a_root = new filesystem::Directory (dir);
165    
166    load (a_root, maxLevel);
167    
168    a_root->print ();
169    cout << endl;
170
171    forward (a_root);
172       
173    writeContext ("file.context");
174 }  
175
176 xml::Node* WorkDirectory::asXML (xml::Node* parent) const
177    throw ()
178 {
179    xml::Node* result = app::Application::asXML (parent);
180    a_repository.asXML (result);
181    return result;
182 }
183
184 void WorkDirectory::forward (filesystem::Directory* dir)
185    throw (RuntimeException)
186 {
187    cout << "forward: " << dir->getPath () << endl;
188    
189    for (filesystem::Directory::child_iterator ii = dir->child_begin (), maxii = dir->child_end (); ii != maxii; ii ++) {
190       dir = filesystem::Directory::down_cast (filesystem::Directory::child (ii));
191       
192       if (dir == NULL) 
193          continue;
194      
195       try { 
196          instantiateOne (dir);
197          fullCache (dir, a_files, Flags::Clear);
198          reuseHoles (dir, a_files);
199          destroyObjects (dir, a_files);
200          forward (dir);      
201       }
202       catch (RuntimeException& ex) {
203          ex.trace ();
204       }
205    }   
206 }
207
208 /*
209  * Crea una serie de instancia simultáneas sobre el mismo objeto para verificar que sólo lo carga 
210  * de verdad sea necesario.
211  */ 
212 void WorkDirectory::instantiateOne (filesystem::Directory* dir) 
213    throw (RuntimeException)
214 {
215    TraceMethod tm ("WorkDirectory", "instantiateOne", ANNA_FILE_LOCATION);
216    
217    cout << "WorkDirectory::instantiateOne: Instancia varias veces la misma instancia para verificar el reuso" << endl;
218    
219    storage::Directory* aux;
220
221    {
222       dbos::AutoObject <storage::Directory> root1;   
223       aux = root1 = storage::Directory::instantiate (dir);
224       message ("Root1", aux);
225       
226       dbos::AutoObject <storage::Directory> root2;   
227       aux = root2 = storage::Directory::instantiate (dir);
228       message ("Root2", aux);
229    }
230    
231    dbos::AutoObject <storage::Directory> root3;   
232    aux = root3 = storage::Directory::instantiate (dir);
233    message ("Root3", aux);
234
235    message ("StorageArea", storage::File::getStorageArea ());
236
237    cout << endl;
238 }
239
240 void WorkDirectory::fullCache (filesystem::Directory* dir, WorkDirectory::file_container& files, const int flags) 
241    throw (RuntimeException)
242 {
243    TraceMethod tm ("WorkDirectory", "fullCache", ANNA_FILE_LOCATION);
244    
245    cout << "WorkDirectory::fullCache: Llena la cache de objetos para verificar que crece tanto como sea necesario" << endl;
246
247    filesystem::File* file;
248    
249    int maxSize = storage::File::getMaxSize ();
250    
251    maxSize += rand () % maxSize;
252    
253    for (filesystem::Directory::child_iterator ii = dir->child_begin (), maxii = dir->child_end (); ii != maxii; ii ++) {
254       file = filesystem::File::down_cast (filesystem::Directory::child (ii));
255       
256       if (file != NULL) {
257          storage::File* storageFile = storage::File::instantiate (file);
258          message ("File", storageFile);
259          files.push_back (storageFile);
260          
261 //         if (files.size () >= maxSize)
262 //            break;
263       }
264    }
265      
266    message ("StorageArea (full)", storage::File::getStorageArea ());
267
268    if (flags & Flags::Clear)
269       clear (files);
270    
271    message ("StorageArea (empty)", storage::File::getStorageArea ());
272    
273    cout << endl;
274 }
275
276 void WorkDirectory::reuseHoles (filesystem::Directory* dir, WorkDirectory::file_container& files)
277    throw (RuntimeException)
278 {
279    TraceMethod tm ("WorkDirectory", "reuseHoles", ANNA_FILE_LOCATION);
280    
281    cout << "WorkDirectory::reuseHoles: Invoca dos veces a fullCache para verificar que el tamaño se mantiene la 2ª vez" << endl;   
282    fullCache (dir, files, Flags::Clear);
283    fullCache (dir, files, Flags::Clear);      
284    cout << endl;
285 }
286
287 void WorkDirectory::destroyObjects (filesystem::Directory* dir, WorkDirectory::file_container& files)
288    throw (RuntimeException)
289 {
290    TraceMethod tm ("WorkDirectory", "destroyObjects", ANNA_FILE_LOCATION);
291    
292    cout << "WorkDirectory::destroyObjects: Carga un directorio distinto, para verificar que destruye los objetos según se dejan de utilizar" << endl;   
293    filesystem::File* file;
294    filesystem::Directory* other = NULL;
295    
296    for (filesystem::Directory::child_iterator ii = dir->child_begin (), maxii = dir->child_end (); ii != maxii && other == NULL; ii ++) 
297       other = filesystem::Directory::down_cast (filesystem::Directory::child (ii));    
298          
299    if (other == NULL) {
300       cout << dir->getPath () << ": No se puede realizar esta prueba" << endl << endl;
301       return;
302    }
303    
304    cout << "New Directory: " << other->getPath () << endl;   
305    dir = other;
306    
307    for (filesystem::Directory::child_iterator ii = dir->child_begin (), maxii = dir->child_end (); ii != maxii; ii ++) {
308       file = filesystem::File::down_cast (filesystem::Directory::child (ii));
309       
310       if (file != NULL) {
311          storage::File* storageFile = storage::File::instantiate (file);
312          message ("File", storageFile);
313          storage::File::release (storageFile);         
314       }
315    }
316    
317    message ("StorageArea", storage::File::getStorageArea ());
318    
319    cout << endl;
320 }
321
322
323 void WorkDirectory::clear (WorkDirectory::file_container& files)
324    throw ()
325 {
326    storage::File* file;
327    
328    /* Libera los objetos en distinto orden para empeorar el tratamiento huecos */
329
330    if ((anna::functions::millisecond () % 2) == 0) {
331       cout << "Clear directo" << endl;
332       for (file_iterator ii = files.begin (), maxii = files.end (); ii != maxii; ii ++) {
333          file = *ii;
334          storage::File::release (file);
335       }      
336    }
337    else {
338       cout << "Clear inverso" << endl;
339       for (file_reverse_iterator ii = files.rbegin (), maxii = files.rend (); ii != maxii; ii ++) {
340          file = *ii;
341          storage::File::release (file);
342       }            
343    }
344    
345    files.clear ();
346 }
347
348 /*static*/
349 void WorkDirectory::load (filesystem::Directory* parent, const int maxLevel, const int level) 
350    throw (RuntimeException)
351 {
352    if (level == maxLevel)
353       return;
354    
355    io::Directory directory;
356    string fullPath;
357    
358    directory.read (parent->getPath (), io::Directory::Mode::ShortPath);
359    
360    for (io::Directory::const_iterator ii = directory.begin (), maxii = directory.end (); ii != maxii; ii ++) { 
361       const std::string& name = io::Directory::data (ii);
362       
363       fullPath = filesystem::Abstract::calculePath (parent, name);
364       
365       if (io::functions::isADirectory (fullPath)) {
366          try {
367             filesystem::Directory* dd = new filesystem::Directory (parent, name);
368             load (dd, maxLevel, level + 1);
369          }
370          catch (RuntimeException& ex) {
371             ex.trace ();
372          }
373       }
374       else {
375          // Se asociado al parent automáticamente.
376          filesystem::File* ff = new filesystem::File (parent, name);         
377       }
378    }      
379 }