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__