00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 #ifndef __loaded__txmem_cpp__
00021 #define __loaded__txmem_cpp__
00022 using namespace std;
00023 #line 1 "txmem.c++"
00024 #include <time.h>
00025 #include <errno.h>
00026 #include <unistd.h>
00027 #include <sys/types.h>
00028 #include <assert.h>
00029 #include <sys/mman.h>
00030 #include <sys/stat.h>
00031 #include <fcntl.h>
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include "pagemap.h"
00036 #include <vector>
00037 #include "txmem.h"
00038 using namespace std;
00039 
00040 #define RF 10
00041 #define RANDOM_BREAKS
00042 #define RIGID_FLAGS
00043 
00044 TxMemory::TxMemory(const char* filename, unsigned long size)
00045 {
00046   pagesize=getpagesize();
00047   assert(pagesize>0);
00048   pagecount=1+(size-1)/pagesize;
00049 #ifdef DEBUG
00050   printf("Requires %d pages\n",pagecount);
00051 #endif
00052   memory_size=pagecount*pagesize;
00053   
00054   
00055   char T[1000];
00056   sprintf(T,"%s.journal",filename);
00057   journalfn=strdup(T);
00058   sprintf(T,"%s.journal.tmp",filename);
00059   journaltmp=strdup(T);
00060   sprintf(T,"%s.memory",filename);
00061   char* memoryfn=strdup(T);
00062 
00063   int journal=open(journalfn,O_RDWR);
00064   if (journal==-1 && errno==ENOENT)
00065     journal=0;
00066   assert(journal>=0);
00067   
00068   
00069   int err;
00070   fd=open(memoryfn, O_RDWR);
00071   if (fd<=0)
00072     {
00073       fd=open(memoryfn, O_CREAT|O_RDWR,S_IRUSR|S_IWUSR);
00074 #ifdef DEBUG
00075       printf("Created memory file %s\n",memoryfn);
00076 #endif
00077       assert(fd);
00078       
00079       err=ftruncate(fd,memory_size);
00080       assert(!err);
00081       ftruncate(journal,0);
00082     }
00083   assert(fd);
00084   
00085   
00086   if (journal)
00087     {
00088       long long journal_size=lseek(journal,0,SEEK_END);
00089       assert(journal_size>sizeof(int));
00090       int journalpagesize;
00091       lseek(journal,0,SEEK_SET);
00092       int R=read(journal,&journalpagesize,sizeof(int));
00093       assert(R==sizeof(int));
00094       printf("Reading memory journal");
00095       fflush(stdout);
00096       int blocksize=journalpagesize+sizeof(int);
00097       assert((journal_size-sizeof(int))%blocksize==0);
00098       int entries=(journal_size-sizeof(int))/blocksize;
00099       for(int i = 0 ; i < entries; i++)
00100         {
00101           int journalpos=sizeof(int)+i*blocksize;
00102           int pos=lseek(journal,journalpos,SEEK_SET);
00103           assert(pos==journalpos);
00104           int pageno;
00105           char buffer[journalpagesize];
00106           R=read(journal,&pageno,sizeof(int));
00107           assert(R==sizeof(int));
00108           R=read(journal,buffer,journalpagesize);
00109           assert(R==journalpagesize);
00110           pos=lseek(fd,pageno*journalpagesize,SEEK_SET);
00111           assert(pos==pageno*journalpagesize);
00112           printf(" %d",pageno);
00113           int W=write(fd,buffer,journalpagesize);
00114 #ifdef RANDOM_BREAKS
00115           if (random()%(entries*RF)==0)
00116             exit(13);
00117 #endif
00118           assert(W==journalpagesize);
00119         }
00120       err=fdatasync(fd);
00121       assert(!err);
00122       err=close(journal);
00123       assert(!err);
00124 #ifdef RANDOM_BREAKS
00125       if (random()%(4*RF)==0)
00126         exit(14);
00127 #endif
00128       err=remove(journalfn);
00129       assert(!err);
00130       printf(" [done]\n");
00131     }
00132   
00133   
00134   M=NULL;
00135   reopen_map();
00136   
00137   
00138   mapfd=open("/proc/self/pagemap",O_RDONLY);
00139   assert(mapfd>0);
00140   pageflags=open("/proc/kpageflags",O_RDONLY);
00141   assert(pageflags>0);    
00142 }
00143 
00144 void TxMemory::reopen_map()
00145 {
00146   if (M)
00147     munmap(M,memory_size);
00148   char* bef=M;
00149   M=(char*)mmap(M, memory_size, PROT_READ|PROT_WRITE, MAP_PRIVATE,fd,0);
00150   assert(M!=(char*)-1);
00151   assert(M);
00152   if (bef) assert(bef==M);
00153 };
00154 
00155 
00156 unsigned long long TxMemory::commit()
00157 {
00158   unsigned long long target=((unsigned long)(void*)M);
00159   
00160   target/=pagesize;
00161   
00162   int err=lseek64(mapfd, target*8, SEEK_SET);
00163   assert(err==target*8);
00164   assert(sizeof(long long)==8);
00165   unsigned long long page2pfn[pagecount];
00166   err=read(mapfd,page2pfn,sizeof(long long)*pagecount);
00167   if (err<0)
00168     perror("Reading pagemap");
00169   if(err!=pagecount*8)
00170     printf("Could only read %d bytes\n",err);
00171   
00172   vector<int> changed_pages;
00173   for(int i = 0 ; i < pagecount; i++)
00174     {
00175       unsigned long long v2a=page2pfn[i];
00176       if (v2a==0) continue; 
00177       int this_page_size=(PM_PSHIFT_MASK&v2a)>>PM_PSHIFT_OFFSET;
00178       assert(1<<this_page_size==pagesize);
00179       v2a&=~PM_PSHIFT_MASK;
00180       
00181       if(v2a&0x8000000000000000LL) 
00182         {
00183           unsigned long long pfn=PM_PFRAME(v2a);
00184           
00185           err=lseek64(pageflags,pfn*8,SEEK_SET);
00186           assert(err==pfn*8);
00187           unsigned long long pf;
00188           err=read(pageflags,&pf,8);
00189           assert(pf&(1LL<<KPF_MMAP));
00190           pf&=~(1LL<<KPF_MMAP);
00191           pf&=~(1LL<<KPF_LRU);
00192           pf&=~(1LL<<KPF_ACTIVE);
00193           if ((pf&(1<<KPF_SWAPBACKED)) || (pf&(1<<KPF_SWAPCACHE)))
00194             {
00195               changed_pages.push_back(i);
00196 #ifdef RIGID_FLAGS
00197               if (pf!=0x5008)
00198                 {
00199                   printf("Unknown page flags 1 %llx\n",pf);
00200                   fflush(stdout);
00201                   exit(10);
00202                 }
00203 #endif
00204             }
00205 #ifdef RIGID_FLAGS
00206           else
00207             {
00208               
00209               
00210               pf&=~(1LL<<KPF_PRIVATE);      
00211               
00212               
00213               
00214               pf&=~(1LL<<KPF_REFERENCED); 
00215               
00216               
00217               assert(pf&(1LL<<KPF_UPTODATE));
00218               pf&=~(1LL<<KPF_UPTODATE); 
00219               pf&=~(1LL<<KPF_MAPPEDTODISK); 
00220               if (pf!=0)
00221                 {
00222                   printf("Unknown page flags 2 %llx\n",pf);
00223                   fflush(stdout);
00224                   exit(10);
00225                 }
00226             }
00227 #endif
00228         }
00229       else if (v2a==0) continue;
00230       
00231       
00232       else 
00233         printf("Page: %d, flag %llx\n",i,page2pfn[i]);
00234     }
00235   if (changed_pages.size()==0) return 0;
00236   
00237   printf("Writing memory journal"); fflush(stdout);
00238   int journal=open(journaltmp,O_CREAT|O_RDWR|O_TRUNC,S_IRUSR|S_IWUSR);
00239   assert(journal>0);
00240   int pos=lseek(journal,0,SEEK_END);
00241   assert(pos==0);
00242   int ps=pagesize;
00243   int w=write(journal,&ps,sizeof(int));
00244   assert(w==sizeof(int));
00245   for(int j = 0 ; j < changed_pages.size(); j++)
00246     {
00247       int pageno=changed_pages[j];
00248       int written=write(journal,&pageno,sizeof(int));
00249       assert(written==sizeof(int));
00250       written=write(journal,M+(pageno*pagesize),pagesize);
00251       assert(written==pagesize);
00252     }
00253 #ifdef RANDOM_BREAKS
00254   if (random()%(4*RF)==0)
00255     exit(10);
00256 #endif
00257   err=fdatasync(journal);
00258   assert(!err);
00259   err=close(journal);
00260   assert(!err);
00261   err=rename(journaltmp,journalfn);
00262   assert(!err);
00263   printf(" [done]\n");
00264   
00265   printf("Committing pages:");
00266   for(int j = 0 ; j < changed_pages.size(); j++)
00267     {
00268       int pageno=changed_pages[j];
00269       printf(" %d",pageno);
00270       unsigned long long pos=lseek(fd,pageno*pagesize,SEEK_SET);
00271       assert(pos==pageno*pagesize);
00272       
00273 #ifdef RANDOM_BREAKS
00274       if (random()%(changed_pages.size()*RF*2)==0)
00275         exit(11);
00276 #endif
00277       int written=write(fd,M+pageno*pagesize,pagesize);
00278       assert(written==pagesize);
00279     }
00280   printf(" [done]\n");
00281   err=fdatasync(fd);
00282   assert(!err);
00283   
00284   
00285 #ifdef RANDOM_BREAKS
00286   if (random()%(RF*4)==0)
00287     exit(12);
00288 #endif
00289   err=remove(journalfn);
00290   assert(!err);
00291   
00292   reopen_map();
00293   return changed_pages.size()*pagesize;
00294 }
00295 
00296 void TxMemory::abort()
00297 {
00298   reopen_map();
00299 }
00300 
00301 
00302 
00303 
00304 
00305 
00306 #endif // __loaded__txmem_cpp__