00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 #include <stdb.h>
00062
00063
00065
00067
00068 Tstdb::Tstdb(const char *TCDBName, const char *TCDBLogName, const int ParMaxLogSize, const int ParMaxTime){
00069
00070
00071 MaxLogSize = ParMaxLogSize;
00072
00073
00074 MaxTime = ParMaxTime * 24 * 60 * 60;
00075
00076
00077 db=strdup(TCDBName);
00078 log=strdup(TCDBLogName);
00079
00080
00081 Initialize();
00082 }
00083
00084
00086
00088
00089 void Tstdb::Initialize(void){
00090
00091
00092 int ReadBytesTran = 0;
00093
00094 char dbtmp[100];
00095 sprintf(dbtmp, "%s.tmp", db);
00096
00097
00098
00099
00100 ifstream fdtmp(dbtmp, ios::in);
00101 if(fdtmp)
00102 rename(dbtmp,db);
00103 fdtmp.close();
00104
00105
00106
00107
00108 ifstream cdbIn(db , ios::in);
00109 if(!cdbIn){
00110
00111 OpenCDBStatus=CDBNOFILE;
00112 }
00113 else{
00114
00115 OpenCDBStatus=CDBOK;
00116
00117
00118
00119 string buffer;
00120 while (!cdbIn.eof()){
00121 bool final;
00122 TAction action;
00123 if (!Getcdbline(cdbIn, action, final)){
00124
00125 OpenCDBStatus=CDBCORRUPTION;
00126 break;
00127 }
00128 if(!final){
00129
00130 DBMemory.insert(TValue(action.GetKey(),action.GetData()));
00131 }
00132 }
00133 }
00134
00135
00136 ifstream logIn(log, ios::in);
00137 if (!logIn){
00138
00139 OpenLogStatus=LogNOFILE;
00140 }
00141 else{
00142
00143 ReadBytes=0;
00144
00145 string buffer;
00146 while (!logIn.eof()){
00147
00148 bool commit, final;
00149 int size;
00150 TAction action;
00151
00152 if (!Getlogline(logIn, action, commit, size, final)){
00153
00154 OpenLogStatus=LogCORRUPTION;
00155 break;
00156 }
00157 if(final) continue;
00158 if(commit){
00159
00160 ReadBytes+=ReadBytesTran+2;
00161 ReadBytesTran = 0;
00162
00163 while(!RollBack.empty()){
00164 RollBack.pop();
00165 }
00166 }
00167 else{
00168
00169 ReadBytesTran+=size;
00170
00171
00172 TDBMemory::iterator p = DBMemory.find(action.GetKey());
00173
00174
00175 switch(action.GetFunction()){
00176 case DELETE:
00177
00178 if (p != DBMemory.end()){
00179
00180
00181 TAction action2(INSERT, action.GetKey(), p->second);
00182 RollBack.push(action2);
00183
00184 DBMemory.erase(action.GetKey());
00185 }
00186 else{
00187
00188
00189 }
00190 break;
00191
00192 case UPDATE:
00193 case INSERT:
00194
00195 if (p != DBMemory.end()){
00196
00197
00198
00199 TAction action2(UPDATE, action.GetKey(), action.GetData());
00200 RollBack.push(action2);
00201
00202 DBMemory[action.GetKey()] = action.GetData();
00203 }
00204 else{
00205
00206
00207
00208 TAction action2(DELETE, action.GetKey(), "");
00209 RollBack.push(action2);
00210
00211 DBMemory.insert(TValue(action.GetKey(),action.GetData()));
00212 }
00213 break;
00214 }
00215 }
00216 }
00217
00218 if (OpenLogStatus == LogCORRUPTION){
00219
00220 Rollback();
00221
00222 truncate(log, ReadBytes);
00223 }
00224 else
00225 OpenLogStatus=LogOK;
00226 }
00227 }
00228
00229
00231
00233
00234 bool Tstdb::Getcdbline(ifstream &in, TAction &action, bool &final){
00235
00236
00237 char c;
00238 in.get(c);
00239 if (in.eof()) return false;
00240 if (c=='\n'){
00241 final=true;
00242 in.get(c);
00243 return true;
00244 }
00245 final=false;
00246 if(c!='+') return false;
00247
00248 int size;
00249 return Getline(in, action, size);
00250 }
00251
00252
00254
00256
00257 bool Tstdb::Getlogline(ifstream &in, TAction &action, bool &commit, int &size, bool &final){
00258
00259
00260 char c;
00261 in.get(c);
00262 if (in.eof()){
00263
00264 final = true;
00265 in.get(c);
00266 return true;
00267 }
00268 final = false;
00269 if(c==COMMIT){
00270
00271 commit = true;
00272
00273
00274 in.get(c);
00275 if(in.eof()) return false;
00276 if(c!='\n') return false;
00277 size = 2;
00278 return true;
00279 }
00280 else{
00281
00282 commit = false;
00283 if(c!='+') return false;
00284 return Getline(in, action, size);
00285 }
00286 }
00287
00288
00290
00292
00293 bool Tstdb::Getline(ifstream &in, TAction &action, int &size){
00294
00295
00296 char buffer[BUFFSIZE],c;
00297 size=1;
00298 in.get(buffer, BUFFSIZE, ',');
00299 int lkey;
00300 lkey = atol(buffer);
00301 size+=strlen(buffer);
00302 in.get(c);
00303 if (in.eof())
00304 return false;
00305 if(c!=',')
00306 return false;
00307 size+=1;
00308
00309
00310
00311 int ldata;
00312
00313 in.get(buffer, BUFFSIZE, ':');
00314 if (in.eof())
00315 return false;
00316 if(buffer[0]=='-'){
00317
00318 in.get(buffer[1]);
00319 if (in.eof())
00320 return false;
00321 if(buffer[1]=='1'){
00322 ldata=0;
00323 size+=2;
00324 }
00325 else{
00326
00327 return false;
00328 }
00329 }
00330 else{
00331
00332 if (in.eof())
00333 return false;
00334 ldata = atol(buffer);
00335 size+=strlen(buffer);
00336 }
00337
00338 in.get(c);
00339 if (in.eof())
00340 return false;
00341 if(c!=':')
00342 return false;
00343 size+=1;
00344
00345
00346 in.read(buffer, lkey);
00347 if (in.eof())
00348 return false;
00349 string keys(buffer, buffer+lkey);
00350 size+=lkey;
00351
00352
00353
00354 in.get(c);
00355 if (in.eof()) return false;
00356 if(c!='-') return false;
00357 in.get(c);
00358 if (in.eof()) return false;
00359 if(c!='>') return false;
00360 size+=2;
00361
00362
00363
00364 if(ldata == 0){
00365
00366 TAction action1(DELETE,keys,"");
00367 action=action1;
00368 }
00369 else{
00370
00371 in.read(buffer, ldata);
00372 string datas(buffer, buffer+ldata);
00373 TAction action1(INSERT,keys,datas);
00374 action=action1;
00375 }
00376 size+=ldata;
00377
00378
00379 in.get(c);
00380 if (in.eof())
00381 return false;
00382 if(c!='\n')
00383 return false;
00384 size+=1;
00385 return true;
00386 }
00387
00388
00390
00392
00393 bool Tstdb::Update(char *key,unsigned int lkey, char *data, unsigned int ldata){
00394 string keys(key,key+lkey);
00395 string datas(data,data+ldata);
00396
00397 TDBMemory::iterator p = DBMemory.find(keys);
00398 if (p != DBMemory.end()){
00399
00400
00401 TAction action1(UPDATE, keys, p->second);
00402 RollBack.push(action1);
00403
00404
00405 TAction action2(UPDATE, keys, datas);
00406 RedoLog.push(action2);
00407
00408
00409 DBMemory[keys] = datas;
00410
00411 return true;
00412 }
00413 else{
00414
00415
00416 return false;
00417 }
00418 }
00419
00420
00422
00424
00425 bool Tstdb::Insert(char *key,unsigned int lkey, char *data, unsigned int ldata){
00426 string keys(key,key+lkey);
00427 string datas(data,data+ldata);
00428
00429 TDBMemory::iterator p = DBMemory.find(keys);
00430 if (p != DBMemory.end()){
00431
00432
00433 return false;
00434 }
00435 else{
00436
00437
00438 TAction action1(DELETE, keys, "");
00439 RollBack.push(action1);
00440
00441
00442 TAction action2(INSERT, keys, datas);
00443 RedoLog.push(action2);
00444
00445
00446 DBMemory.insert(TValue(keys,datas));
00447 return true;
00448 }
00449 }
00450
00451
00453
00455
00456 bool Tstdb::Fetch(char *key,unsigned int lkey, const char **data, unsigned int *ldata){
00457 string keys(key,key+lkey);
00458
00459 TDBMemory::iterator p = DBMemory.find(keys);
00460 if (p != DBMemory.end()){
00461
00462 *ldata = p->second.length();
00463 *data = p->second.c_str();
00464 return true;
00465 }
00466 else{
00467
00468 return false;
00469 }
00470 }
00471
00472
00474
00476
00477 bool Tstdb::Delete(char *key,unsigned int lkey){
00478 string keys(key,key+lkey);
00479
00480 TDBMemory::iterator p = DBMemory.find(keys);
00481 if (p != DBMemory.end()){
00482
00483
00484 TAction action1(INSERT, keys, p->second);
00485 RollBack.push(action1);
00486
00487
00488 TAction action2(DELETE, keys, "");
00489 RedoLog.push(action2);
00490
00491
00492 DBMemory.erase(keys);
00493
00494 return true;
00495 }
00496 else{
00497
00498
00499 return false;
00500 }
00501 }
00502
00503
00505
00507
00508 bool Tstdb::Commit(void){
00509
00510
00511 if(RedoLog.empty())
00512 return true;
00513
00514
00515
00516 ofstream logOut(log, ios::out|ios::app);
00517 while(!RedoLog.empty()){
00518 TAction &action = RedoLog.front();
00519
00520 switch(action.GetFunction()){
00521
00522 case INSERT:
00523
00524 case UPDATE:{
00525
00526
00527 string buffer;
00528 ParserLineOut(buffer, action);
00529
00530 logOut << buffer;
00531 break;
00532 }
00533 case DELETE:{
00534
00535
00536 string buffer;
00537 ParserLineDeleteOut(buffer, action);
00538
00539 logOut << buffer;
00540 break;
00541 }
00542 }
00543 RedoLog.pop();
00544 }
00545
00546
00547 logOut << COMMIT << endl;
00548
00549
00550 logOut.flush();
00551
00552
00553
00554 while(!RollBack.empty())
00555 RollBack.pop();
00556
00557
00558 ReorganizeNecessary();
00559
00560 return true;
00561 }
00562
00563
00565
00567
00568 bool Tstdb::ParserLineOut(string &line, TAction &action){
00569 char buffer[100];
00570
00571
00572
00573 sprintf(buffer, "+%lu,%lu:", (unsigned long)action.GetKey().size(),
00574 (unsigned long)action.GetData().size());
00575 char *d;
00576 d=buffer+strlen(buffer);
00577 memmove(d,action.GetKey().c_str(), action.GetKey().size());
00578 d+=action.GetKey().size();
00579 *(d++)='-';
00580 *(d++)='>';
00581 memmove(d,action.GetData().c_str(), action.GetData().size());
00582 d+=action.GetData().size();
00583 *(d++)='\n';
00584
00585 string linetmp(buffer,d);
00586 line = linetmp;
00587
00588 return true;
00589 }
00590
00591
00593
00595
00596 bool Tstdb::ParserLineDeleteOut(string &line, TAction &action){
00597 char buffer[100];
00598
00599
00600 sprintf(buffer, "+%lu,-1:", (unsigned long) action.GetKey().size());
00601
00602 char *d;
00603 d=buffer+strlen(buffer);
00604 memmove(d,action.GetKey().c_str(), action.GetKey().size());
00605 d+=action.GetKey().size();
00606 *(d++)='-';
00607 *(d++)='>';
00608 *(d++)='\n';
00609
00610 string linermp(buffer,d);
00611 line = linermp;
00612
00613 return true;
00614 }
00615
00616
00618
00620
00621 bool Tstdb::Rollback(void){
00622
00623
00624 while(!RollBack.empty()){
00625 TAction &action = RollBack.top();
00626 switch(action.GetFunction()){
00627
00628 case INSERT:
00629
00630 DBMemory.insert(TValue(action.GetKey(),action.GetData()));
00631 break;
00632
00633 case UPDATE:
00634
00635 DBMemory[action.GetKey()] = action.GetData();
00636 break;
00637
00638 case DELETE:
00639
00640 DBMemory.erase(action.GetKey());
00641 break;
00642 }
00643 RollBack.pop();
00644 }
00645
00646
00647
00648 while(!RedoLog.empty())
00649 RedoLog.pop();
00650
00651 return true;
00652 }
00653
00654
00656
00658
00659 bool Tstdb::Reorganize(){
00660
00661 Rollback();
00662
00663
00664 char dbtmp[100];
00665 sprintf(dbtmp, "%s.tmp", db);
00666 rename(db, dbtmp);
00667
00668
00669 ofstream cdbOut(db);
00670 if (!cdbOut){
00671 return false;
00672 }
00673
00674
00675
00676 TDBMemory::iterator DBIter = DBMemory.begin();
00677
00678
00679 while (DBIter != DBMemory.end()){
00680 TAction action(INSERT,DBIter->first, DBIter->second);
00681
00682 string buffer;
00683 ParserLineOut(buffer, action);
00684 cdbOut << buffer;
00685 DBIter++;
00686 }
00687
00688
00689 cdbOut << endl;
00690
00691
00692 unlink(log);
00693
00694
00695 unlink(dbtmp);
00696
00697 return true;
00698 }
00699
00700
00702
00704
00705 bool Tstdb::ReorganizeNecessary(){
00706
00707 struct stat file_cdb_stats;
00708 struct stat file_log_stats;
00709
00710 if (stat(log, &file_log_stats)!=-1){
00711
00712
00713 if (file_log_stats.st_size > MaxLogSize)
00714 return Reorganize();
00715
00716
00717 if (stat(db, &file_cdb_stats)!=-1){
00718 if(difftime(file_log_stats.st_mtime, file_cdb_stats.st_mtime) > MaxTime)
00719 return Reorganize();
00720 }
00721 }
00722 return true;
00723 }
00724
00725
00727
00729
00730 bool Tstdb::Firstkey(const char **key,unsigned int *lkey, const char **data, unsigned int *ldata){
00731
00732 index = DBMemory.begin();
00733
00734
00735 if (index == DBMemory.end())
00736 return false;
00737
00738 *lkey = index->first.length();
00739 *key = index->first.c_str();
00740
00741 *ldata = index->second.length();
00742 *data = index->second.c_str();
00743
00744 index++;
00745
00746 return true;
00747 }
00748
00749
00751
00753
00754 bool Tstdb::Nextkey(const char **key,unsigned int *lkey, const char **data, unsigned int *ldata){
00755
00756
00757 if (index == DBMemory.end())
00758 return false;
00759
00760 *lkey = index->first.length();
00761 *key = index->first.c_str();
00762
00763 *ldata = index->second.length();
00764 *data = index->second.c_str();
00765
00766 index++;
00767
00768 return true;
00769 }
00770
00774
00775
00776
00777
00778
00779
00780
00782
00784
00785 Tstdb::~Tstdb(){
00786 }