Main Page | Modules | Namespace List | Class Hierarchy | Class List | File List | Class Members | File Members

DbjLatch.cpp

Go to the documentation of this file.
00001 /*************************************************************************\ 00002 * * 00003 * (C) 2004 * 00004 * Lehrstuhl fuer Datenbanken und Informationssysteme * 00005 * Friedrich-Schiller-Universitaet Jena * 00006 * Ernst-Abbe-Platz 1-2 * 00007 * 07745 Jena * 00008 * * 00009 \*************************************************************************/ 00010 00011 #include "DbjLatch.hpp" 00012 00013 #include <sys/types.h> // sem*() 00014 #include <sys/ipc.h> // sem*() 00015 #include <sys/sem.h> // sem*() 00016 #include <sys/stat.h> // S_I* Makros 00017 #include <errno.h> // errno 00018 00019 // Auf Cygwin haben wir das Problem, dass beim Beenden eines Prozesses ein 00020 // Teil der "UNDO" Informationen der Latches verloren gehen. Insbesondere 00021 // hatten wir beim Testen den Fall, dass ein "Shared" Latch angefordert wurde, 00022 // anschliessend auch wieder freigegeben (sharedCount war auf 0), und nach dem 00023 // Ende des Testprogramms war (sharedCount ploetzlich auf 1). Also wurde das 00024 // letzte Verringern des sharedCount "vergessen" bzw. die UNDO-Operation 00025 // dafuer faelschlicherweise durchgefuehrt. 00026 // Um das Problem zu loesen, schalten wir fuer Cygwin die UNDO-Funktionalitaet 00027 // aus. Das kann zwar Probleme verursachen, wenn ein Prozess abstuerzt, aber 00028 // besser so als wenn wir unverstaendliche "Hangs" im normalen Betrieb haben. 00029 #if defined(DBJ_CYGWIN) 00030 #if defined(SEM_UNDO) 00031 #undef SEM_UNDO 00032 #endif /* SEM_UNDO */ 00033 #define SEM_UNDO 0 00034 #endif /* DBJ_CYGWIN */ 00035 00036 00037 // Komponente zu der Latches gehoeren 00038 static const DbjComponent componentId = Support; 00039 00040 // Sperre fuer das Erhoehen der Semaphoren-Zaehler wenn Exclusive Latch 00041 // erteilt werden soll 00042 static const Uint16 DBJ_LATCH_BLOCK_NEW_SHARED = 0; 00043 // Nummer der Semaphore, die die Anzahl der "Shared" Nutzer zaehlt 00044 static const Uint16 DBJ_LATCH_SHARED_COUNTER = 1; 00045 // Nummer der Semaphore, die den "Exclusive" Zugriff regelt 00046 static const Uint16 DBJ_LATCH_EXCLUSIVE = 2; 00047 00048 00049 // Initialisiere Latch 00050 DbjErrorCode DbjLatch::initialize() 00051 { 00052 Uint16 semValue[3]; 00053 int semRc = 0; 00054 00055 DBJ_TRACE_ENTRY(); 00056 00057 // erzeuge einen Semaphore-Set mit 3 Semaphoren und speichere ID des Sets 00058 // im Latch (im Shared Memory) 00059 // 00060 // die 3 Semaphoren habe folgenden Sinn: 00061 // 1. Sperren vor dem Erhoehen einer Semaphore (Shared/Exclusive Latch) um 00062 // neue Anforderungen eines Shared Latches zu blocken, wenn ein 00063 // Exclusive Latch bereits angefordert wurde. Ohne dies koennten wir 00064 // leicht in Starvation von "Exclusive" Requests laufen. 00065 // 2. Zaehler fuer die "Shared" Nutzer 00066 // 3. Zahler fuer die "Exclusive" Nutzer (maximal 1) 00067 semaphoreId = semget(IPC_PRIVATE, 3, 00068 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); 00069 if (semaphoreId < 0) { 00070 DBJ_SET_ERROR_TOKEN2(DBJ_LATCH_SEM_CREATE_FAIL, semaphoreId, 00071 strerror(errno)); 00072 goto cleanup; 00073 } 00074 DBJ_TRACE_NUMBER(1, "semaphore set id", semaphoreId); 00075 00076 // initialisiere Semaphoren 00077 semValue[DBJ_LATCH_BLOCK_NEW_SHARED] = +1; 00078 semValue[DBJ_LATCH_SHARED_COUNTER] = 0; 00079 semValue[DBJ_LATCH_EXCLUSIVE] = 0; 00080 semRc = semctl(semaphoreId, 0, SETALL, semValue); 00081 if (semRc != 0) { 00082 DBJ_SET_ERROR_TOKEN2(DBJ_LATCH_SEM_OPERATION_FAIL, 00083 errno, strerror(errno)); 00084 destroy(true); 00085 goto cleanup; 00086 } 00087 00088 cleanup: 00089 return DbjGetErrorCode(); 00090 } 00091 00092 00093 // Zerstoere Latch 00094 DbjErrorCode DbjLatch::destroy(bool const force) 00095 { 00096 DbjErrorCode rc = DBJ_SUCCESS; 00097 00098 DBJ_TRACE_ENTRY(); 00099 00100 if (semaphoreId < 0) { 00101 goto cleanup; 00102 } 00103 00104 // hole Semaphoren-Set zuerst 00105 if (!force) { 00106 rc = get(Exclusive); 00107 if (rc != DBJ_SUCCESS) { 00108 DBJ_TRACE_ERROR(); 00109 goto cleanup; 00110 } 00111 } 00112 00113 // zerstoere Semaphoren-Set 00114 { 00115 int semRc = semctl(semaphoreId, 0, IPC_RMID); 00116 if (semRc == -1) { 00117 DBJ_SET_ERROR_TOKEN2(DBJ_LATCH_SEM_DESTROY_WARN, 00118 errno, strerror(errno)); 00119 goto cleanup; 00120 } 00121 } 00122 00123 semaphoreId = -1; 00124 00125 cleanup: 00126 return DbjGetErrorCode(); 00127 } 00128 00129 00130 // Hole Latch 00131 DbjErrorCode DbjLatch::get(LatchMode const mode) 00132 { 00133 int semRc = 0; 00134 DbjErrorCode rc = DBJ_SUCCESS; 00135 struct sembuf semOp[4]; 00136 00137 DBJ_TRACE_ENTRY(); 00138 00139 switch (mode) { 00140 case Shared: 00141 // Verhindere Kollisionen mit einem parallelen "Exclusive" Request 00142 // (warte bis wir das Lock haben), und dann erhoehe "Shared" 00143 // Zaehler. Danach geben wir gleich das Lock frei und erzwingen, 00144 // dass "Exclusive" auf 0 steht. 00145 // Sollte "Exclusive" nicht 0 sein, dann haben wir ein groesseres 00146 // Problem, da wir dann eigentlich das Block nicht haetten kriegen 00147 // duerfen. 00148 semOp[0].sem_num = DBJ_LATCH_BLOCK_NEW_SHARED; 00149 semOp[0].sem_op = -1; // verhindere "Exclusive" Requests 00150 semOp[0].sem_flg = 0; 00151 semOp[1].sem_num = DBJ_LATCH_SHARED_COUNTER; 00152 semOp[1].sem_op = +1; // zaehle "Shared" Nutzer 00153 semOp[1].sem_flg = SEM_UNDO; 00154 semOp[2].sem_num = DBJ_LATCH_BLOCK_NEW_SHARED; 00155 semOp[2].sem_op = +1; // erlaube "Exclusive" Requests 00156 semOp[2].sem_flg = 0; 00157 semOp[3].sem_num = DBJ_LATCH_EXCLUSIVE; 00158 semOp[3].sem_op = 0; 00159 semOp[3].sem_flg = IPC_NOWAIT; // Problem wenn's fehl schlagt!! 00160 semRc = semop(semaphoreId, semOp, 4); 00161 if (semRc != 0) { 00162 DBJ_SET_ERROR_TOKEN2(DBJ_LATCH_SEM_OPERATION_FAIL, 00163 errno, strerror(errno)); 00164 rc = DbjGetErrorCode(); 00165 goto cleanup; 00166 } 00167 break; 00168 00169 case Exclusive: 00170 // Blocke neue "Shared" Requests. Wenn wir dieses Lock haben, dann 00171 // _muss_ der "Exclusive" auf 0 sein. 00172 semOp[0].sem_num = DBJ_LATCH_BLOCK_NEW_SHARED; 00173 semOp[0].sem_op = -1; 00174 semOp[0].sem_flg = SEM_UNDO; 00175 semOp[1].sem_num = DBJ_LATCH_EXCLUSIVE; 00176 semOp[1].sem_op = 0; 00177 semOp[1].sem_flg = IPC_NOWAIT; 00178 semRc = semop(semaphoreId, semOp, 2); 00179 if (semRc != 0) { 00180 DBJ_SET_ERROR_TOKEN2(DBJ_LATCH_SEM_OPERATION_FAIL, 00181 errno, strerror(errno)); 00182 rc = DbjGetErrorCode(); 00183 goto cleanup; 00184 } 00185 00186 // Nun brauchen wir nur noch zu warten, bis alle "Shared" Nutzer 00187 // weg sind und erhalten dann das "Exclusive" Latch. 00188 semOp[0].sem_num = DBJ_LATCH_SHARED_COUNTER; 00189 semOp[0].sem_op = 0; 00190 semOp[0].sem_flg = 0; 00191 semOp[1].sem_num = DBJ_LATCH_EXCLUSIVE; 00192 semOp[1].sem_op = +1; 00193 semOp[1].sem_flg = 0; // a termination on write is deadly! 00194 semRc = semop(semaphoreId, semOp, 2); 00195 if (semRc != 0) { 00196 if (errno != EIDRM) { 00197 // Irgendwas ging schief, also erlauben wir wieder neue 00198 // "Shared" Requests. (Aber nur wenn Semaphoren-Set noch 00199 // existiert und nicht zwischendurch entfernt wurde.) 00200 semOp[0].sem_num = DBJ_LATCH_BLOCK_NEW_SHARED; 00201 semOp[0].sem_op = +1; 00202 semOp[0].sem_flg = SEM_UNDO; 00203 semRc = semop(semaphoreId, semOp, 1); 00204 // das darf jetzt aber nicht schief gehen (ausser 00205 // Semaphoren-Set wurde jetzt geloescht) 00206 } 00207 if (semRc != 0) { 00208 DBJ_SET_ERROR_TOKEN2(DBJ_LATCH_SEM_OPERATION_FAIL, 00209 errno, strerror(errno)); 00210 rc = DbjGetErrorCode(); 00211 } 00212 goto cleanup; 00213 } 00214 break; 00215 } 00216 00217 cleanup: 00218 return rc; 00219 } 00220 00221 00222 // Gib Latch frei 00223 DbjErrorCode DbjLatch::release() 00224 { 00225 int semRc = 0; 00226 DbjErrorCode rc = DBJ_SUCCESS; 00227 struct sembuf semOp[2]; 00228 00229 DBJ_TRACE_ENTRY(); 00230 00231 // Teste ob "Exclusive" auf 0 ist; wenn ja, dann haben wir ein Shared Lock 00232 // und geben dieses gleich mit frei. 00233 semOp[0].sem_num = DBJ_LATCH_EXCLUSIVE; 00234 semOp[0].sem_op = 0; 00235 semOp[0].sem_flg = IPC_NOWAIT; 00236 semOp[1].sem_num = DBJ_LATCH_SHARED_COUNTER; 00237 semOp[1].sem_op = -1; 00238 semOp[1].sem_flg = SEM_UNDO; 00239 semRc = semop(semaphoreId, semOp, 2); 00240 if (semRc != 0) { 00241 if (errno == EAGAIN) { 00242 // "Exclusive" war gesetzt, also geben wir dieses frei 00243 DBJ_TRACE_STRING(10, "removing exclusive latch"); 00244 semOp[0].sem_num = DBJ_LATCH_BLOCK_NEW_SHARED; 00245 semOp[0].sem_op = +1; // erlaube neue "Shared" Requests 00246 semOp[0].sem_flg = SEM_UNDO; 00247 semOp[1].sem_num = DBJ_LATCH_EXCLUSIVE; 00248 semOp[1].sem_op = -1; 00249 semOp[1].sem_flg = 0; // this must work! 00250 semRc = semop(semaphoreId, semOp, 2); 00251 } 00252 if (semRc != 0) { 00253 DBJ_SET_ERROR_TOKEN2(DBJ_LATCH_SEM_OPERATION_FAIL, 00254 errno, strerror(errno)); 00255 rc = DbjGetErrorCode(); 00256 goto cleanup; 00257 } 00258 } 00259 00260 cleanup: 00261 return rc; 00262 } 00263 00264 00265 // Teste auf Shared Latch 00266 DbjErrorCode DbjLatch::getSharedCount(Uint32 &sharedCount) const 00267 { 00268 int semValue = 0; 00269 00270 DBJ_TRACE_ENTRY(); 00271 00272 semValue = semctl(semaphoreId, DBJ_LATCH_SHARED_COUNTER, GETVAL); 00273 if (semValue < 0) { 00274 DBJ_SET_ERROR_TOKEN2(DBJ_LATCH_SEM_OPERATION_FAIL, 00275 errno, strerror(errno)); 00276 goto cleanup; 00277 } 00278 sharedCount = semValue; 00279 00280 cleanup: 00281 return DbjGetErrorCode(); 00282 } 00283 00284 00285 // Teste auf Exclusive Latch 00286 DbjErrorCode DbjLatch::isHeldExclusive(bool &isHeld) const 00287 { 00288 int semValue = 0; 00289 00290 DBJ_TRACE_ENTRY(); 00291 00292 semValue = semctl(semaphoreId, DBJ_LATCH_EXCLUSIVE, GETVAL); 00293 if (semValue < 0) { 00294 DBJ_SET_ERROR_TOKEN2(DBJ_LATCH_SEM_OPERATION_FAIL, 00295 errno, strerror(errno)); 00296 goto cleanup; 00297 } 00298 isHeld = semValue > 0 ? true : false; 00299 00300 cleanup: 00301 return DbjGetErrorCode(); 00302 } 00303 00304 00305 // Teste auf "Unlatched" 00306 DbjErrorCode DbjLatch::isLocked(bool &isLatched) const 00307 { 00308 DbjErrorCode rc = DBJ_SUCCESS; 00309 Uint32 sharedCount = 0; 00310 00311 DBJ_TRACE_ENTRY(); 00312 00313 rc = getSharedCount(sharedCount); 00314 if (rc != DBJ_SUCCESS) { 00315 DBJ_TRACE_ERROR(); 00316 goto cleanup; 00317 } 00318 if (sharedCount > 0) { 00319 isLatched = true; 00320 goto cleanup; 00321 } 00322 rc = isHeldExclusive(isLatched); 00323 if (rc != DBJ_SUCCESS) { 00324 DBJ_TRACE_ERROR(); 00325 goto cleanup; 00326 } 00327 00328 cleanup: 00329 return DbjGetErrorCode(); 00330 } 00331

Generated on Mon Jul 4 15:40:29 2005 for Jenas Datenbanksystem 'System J' by doxygen 1.3.8