Pagina Principale   Moduli   Lista dei namespaces   Gerarchia delle classi   Lista in ordine alfabetico   Lista dei composti   Lista dei files   Membri dei namespaces   Membri dei composti   Membri dei files   Esempi  

/home/fbassi/devel/projects/reti/ObjectManager/Validate.cc

Vai alla documentazione di questo file.
00001 /*
00002  *    FBFS Distributed Object Repository
00003  *    Copyright (C) 2001 Francesco V. Bassi
00004  *
00005  *    This program is free software; you can redistribute it and/or modify
00006  *    it under the terms of the GNU General Public License as published by
00007  *    the Free Software Foundation; either version 2 of the License, or
00008  *    (at your option) any later version.
00009  *
00010  *    This program is distributed in the hope that it will be useful,
00011  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *    GNU General Public License for more details.
00014  *
00015  *    You should have received a copy of the GNU General Public License
00016  *    along with this program; if not, write to the Free Software
00017  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  */
00019 
00020 #include "ObjectManager_i.h"
00021 #include "DataStructures.h"
00022 
00023 #include "../idl/Storage.hh"
00024 #include "../idl/Security.hh"
00025 #include "../Object/Properties.h"
00026 #include "../utils/URI.h"
00027 #include "../utils/NameServer.h"
00028 #include "../utils/Rand.h"
00029 
00030 #include <values.h>
00031 
00032 using namespace utils;
00033 
00044 void fbfs::ObjectManager_i::validate() {
00045     TempRepository tr;
00046     
00047     // PRIMA FASE: Query a tutti gli Storage registrati (nella struttura servers) del
00048     // loro contenuto.
00049     // Creazione della struttura TempRepository, mappa che associa ad ogni Id di oggetto
00050     // l'elenco delle terne <ServerOspitante, Obj_prop, Obj_ts> che rapprenentano ogni
00051     // copia dell'oggetto negli Storage.
00052     for(Servers::iterator it = servers.begin(); it != servers.end(); it++) {
00053         // Per ogni Storage faccio quanto segue:
00054         // - Lo contatto; se non riesco a raggiungerlo lo elimino dalla lista.
00055         // - Eseguo una get_dir e metto aggiorno la struttura tr.
00056         try {
00057             URI uri((*it).c_str());
00058             CORBA::Object_var obj = utils::NameServer::get_object(orb, uri);
00059             fbfs::Storage_var server = fbfs::Storage::_narrow(obj);
00060             if(CORBA::is_nil(server))
00061                 throw NotFound();
00062             
00063             Obj_infoList *list = server->list(cert);
00064             for(int i=0; i<list->length(); i++) {
00065                 Obj_info &info = (*list)[i];
00066                 string name(info.id.name);
00067                 InstanceInfo instance;
00068                 instance.server = (*it);
00069                 instance.prop = info.prop;
00070                 instance.ts = info.ts;
00071                 tr[name].push_front(instance);
00072             };
00073         } catch (...) {
00074             // In caso di errore --qualunque esso sia-- elimino il server dall'elenco.
00075             servers.erase(it);
00076         };
00077     };
00078     // Qui la struttura TempRepository è completa.
00079 
00080     // SECONDA FASE: Validazione della struttura TempRepository (con eventuali operazioni
00081     // sugli storage per riportare la consistenza) e creazione della struttura Repository.
00082     // Procedo come segue:
00083     // - Per ogni oggetto nel TempRepository, invoco una procedura che lo convalidi, occupandosi
00084     //   di rendere consistenti le istanze.
00085     // - Aggiungo ogni oggetto valido nella struttura Repository rep, con l'elenco dei server
00086     //   che lo forniscono.
00087 
00088     rep = Repository();
00089     for( TempRepository::iterator i = tr.begin(); i != tr.end(); i++ ) {
00090         Servers s = validate( (*i).first, (*i).second );
00091         if(s.size() != 0)   
00092             rep[(*i).first] = s;
00093     };
00094 };
00095 
00096 /*
00097 Algoritmo per la verifica e la eventuale ricostituzione della consistenza:
00098 
00099 Data una coppia (nome oggetto, lista<istanze>), eseguo:
00100 
00101 - Individuo tra le istanze quella con il ts più recente. Se vi sono istanze con
00102 ts(istanza) < ts(istanza_con_ts_più_recente), le elimino in quanto esse rappresentano
00103 copie vecchie di oggetti (le elimino anche dagli Storage dove sono contenute).
00104 
00105 - A questo punto Obj_id e Obj_ts sono sistemate. Bisogna individuare il tipo di proprietà
00106 che l'oggetto deve avere. Per fare questo agisco secondo le seguenti regole di sostituzione:
00107 
00108 DON_SAVE -> REPLICATE_ON_CREAT(value_a=0);
00109 REPLICATE_ON_CREAT -> REPLICATE_ALWAYS(value_a=value_a.old);
00110 REPLICATE_ALWAYS -> REPLICATE_MIN_MAX(value_a=value_b=value_a.old);
00111 
00112 Applico solamente le regole di promozione necessarie affinché tutte le istanze abbiano il
00113 medesimo insieme di proprietà.
00114 Queste proprietà saranno la struttura Obj_prop dell'Oggetto definitivo nel repository.
00115 
00116 - Per tutte le istanze con Obj_prop non corretto, le sistemo.
00117 
00118 - Verifico che l'insieme di istanze verifichi globalmente i limiti imposti dalle proprietà,
00119 creando (o distruggendo, ma eventualità molto rara) ulteriori copie.
00120 */
00121 
00122 // Cancella un oggetto da un dato server, ignorando gli errori.
00123 static void remove(const string &server, const string &objname, CORBA::ORB_ptr &orb, const fbfs::Security &cert) {
00124     try {
00125         URI uri(server.c_str());
00126         CORBA::Object_var obj = utils::NameServer::get_object(orb, uri);
00127         fbfs::Storage_var server = fbfs::Storage::_narrow(obj);
00128         if(!CORBA::is_nil(server)) {
00129             fbfs::Obj_id id;
00130             id.name = CORBA::string_dup(objname.c_str());
00131             server->remove(cert, id);
00132         };
00133     } catch (...) {};
00134 };
00135 
00136 fbfs::Servers fbfs::ObjectManager_i::validate(const string &objname, list<InstanceInfo> &infos) {
00137     int ts = MININT;
00138     list<InstanceInfo> newinfos = list<InstanceInfo>();
00139     list<InstanceInfo>::iterator it;
00140     for(it = infos.begin(); it != infos.end(); it++) {
00141         if((*it).ts.time == ts) {
00142             // Bene, aggiungo l'istanza alla lista delle istanze valide
00143             newinfos.push_front(*it);
00144         } else if((*it).ts.time > ts) {
00145             // L'istanza è più recente di quelle in lista, che devono essere quindi
00146             // scartate e inserisco nella lista la nuova istanza.
00147             for(list<InstanceInfo>::iterator i = newinfos.begin(); i != newinfos.end(); i++)
00148                 ::remove((*i).server, objname, orb, cert);
00149             newinfos = list<InstanceInfo>();
00150             newinfos.push_front(*it);
00151             ts = (*it).ts.time;
00152         } else {
00153             // se invece i.ts.time < ts allora devo scartare l'istanza corrente
00154             ::remove((*it).server, objname, orb, cert);
00155         };
00156     };      
00157 
00158     // Qui ho eliminato dal repository le istanze "vecchie" (con ts diverso dal
00159     // ts dell'istanza più recente) e in newinfos ho l'elenco delle istanze valide.
00160     
00161     // Determino le proprietà, estrapolandole dalle proprietà delle istanze.
00162     Obj_prop np;
00163     np.value_a = 0;
00164     np.value_b = 0;
00165     
00166     for(it = newinfos.begin(); it != newinfos.end(); it++) {
00167         Obj_prop &props = (*it).prop;
00168         switch (props.type) {
00169             case Properties::REPLICATE_MIN_MAX :
00170                 if(props.value_b > np.value_b)
00171                     np.value_b = props.value_b;
00172                 if(props.value_a > np.value_a)
00173                     np.value_a = props.value_a;
00174                 break;
00175             case Properties::REPLICATE_ALWAYS :
00176                 if(props.value_a > np.value_b)
00177                     np.value_b = props.value_a;
00178             case Properties::REPLICATE_ON_CREAT :
00179                 if(props.value_a > np.value_a)
00180                     np.value_a = props.value_a;
00181             case Properties::DONT_SAVE :
00182                 ;
00183         };      
00184     };
00185 
00186     if(np.value_b == 0) {
00187         np.type = Properties::REPLICATE_ON_CREAT;
00188         if(np.value_a == 0)
00189             np.type = Properties::DONT_SAVE;
00190     } else if(np.value_a == np.value_b) {
00191         np.type = Properties::REPLICATE_ALWAYS;
00192     } else {
00193         np.type = Properties::REPLICATE_MIN_MAX;
00194     };
00195 
00196     // Ora mi occupo di garantire che il gruppo di istanze soddisfi le proprietà.
00197     // In particolare deve essere (numero istanze) >= min( np.value_a, (numero di server) ).
00198     // Se non sono abbastanza, creo copie delle istanze.
00199 
00200     // Seleziono i server in cui mettere le nuove copie:
00201     Servers tempservers = servers;  // Servers disponibili per metterci copie
00202     Servers newservers;             // Servers già utilizzati
00203     for( it = newinfos.begin(); it != newinfos.end(); it++) {
00204         tempservers.remove( (*it).server );
00205         newservers.push_front( (*it).server );
00206     };
00207     
00208     if(newinfos.size() >= np.value_b || newinfos.size() == servers.size() ) {
00209         // OK. Tutto aposto già.
00210         return newservers;
00211     };
00212 
00213     // Devo creare le istanze rimanenti e metterle su dei server che non le contengano
00214     // già.
00215 
00216     if(np.value_a > servers.size() )
00217         np.value_a = servers.size();
00218         
00219     // Numero di copie da creare
00220     int count = np.value_a - newinfos.size();
00221 
00222     Servers::iterator vecchio = newservers.begin();
00223     Servers::iterator nuovo = tempservers.begin();
00224     
00225     Servers finalservers = newservers;
00226     
00227     // Salto un numero a caso di server in vecchio, così che gli oggetti siano
00228     // disposti uniformemente nei Servers.
00229     for( int n = utils::rand(newservers.size()); n--; nuovo++);
00230     
00231     for(int maxcycles=2*servers.size() ; count && maxcycles  ; nuovo++, vecchio++, count--, maxcycles--) {
00232         if( vecchio == newservers.end() )
00233             vecchio = newservers.begin();
00234         if( nuovo == tempservers.end() )
00235             nuovo = tempservers.begin();
00236 
00237         // Eseguo una copia utilizzando il metodo put_from_peer() del
00238         // nuovo storage dal vecchio storage.
00239         try {
00240             URI uri(*nuovo);
00241             CORBA::Object_var obj = utils::NameServer::get_object(orb, uri);
00242             fbfs::Storage_var server = fbfs::Storage::_narrow(obj);
00243             if(!CORBA::is_nil(server)) {
00244                 Obj_id id;
00245                 id.name = CORBA::string_dup(objname.c_str());
00246                 server->put_from_peer(cert, id, (*vecchio).c_str() );
00247                 finalservers.push_front(*nuovo);
00248             };
00249         } catch (...) {
00250             // Se c'è qualche errore, me ne sbatto e provo su un server nuovo.
00251             count++;
00252         };
00253     };
00254     
00255     return finalservers;
00256 };  

Generato il Thu Feb 15 13:24:56 2001 per A Simple Distributed Object Repository with CORBA & C++. da doxygen1.2.3 scritto da Dimitri van Heesch, © 1997-2000