@@ -23,8 +23,215 @@ RomulusLog gRomLog {};
2323*
2424*
2525*/
26+ #ifdef USE_ESLOCO
27+ #else
28+ mspace create_mspace_with_base (void * base, size_t capacity, int locked);
29+ #endif
30+ //
31+ // Private methods
32+ //
2633
34+ // Copy the data from 'main' to 'back'
35+ void RomulusLog::copyMainToBack () {
36+ uint64_t size = std::min (per->used_size ,g_main_size);
37+ std::memcpy (back_addr, main_addr, size);
38+ flush_range (back_addr, size);
39+ }
40+
41+ // Copy the data from 'back' to 'main'
42+ void RomulusLog::copyBackToMain () {
43+ uint64_t size = std::min (per->used_size ,g_main_size);
44+ std::memcpy (main_addr, back_addr, size);
45+ flush_range (main_addr, size);
46+ }
47+
48+ RomulusLog::RomulusLog () : dommap{true },maxThreads{128 } {
49+ fc = new std::atomic< std::function<void ()>* >[maxThreads*CLPAD];
50+ for (int i = 0 ; i < maxThreads; i++) {
51+ fc[i*CLPAD].store (nullptr , std::memory_order_relaxed);
52+ }
53+ // Filename for the mapping file
54+ if (dommap) {
55+ base_addr = (uint8_t *)0x7fdd40000000 ;
56+ max_size = PM_REGION_SIZE;
57+ // Check if the file already exists or not
58+ struct stat buf;
59+ if (stat (MMAP_FILENAME, &buf) == 0 ) {
60+ // File exists
61+ // std::cout << "Re-using memory region\n";
62+ fd = open (MMAP_FILENAME, O_RDWR|O_CREAT, 0755 );
63+ assert (fd >= 0 );
64+ // mmap() memory range
65+ uint8_t * got_addr = (uint8_t *)mmap (base_addr, max_size, (PROT_READ | PROT_WRITE), MAP_SHARED_VALIDATE | PM_FLAGS, fd, 0 );
66+ if (got_addr == MAP_FAILED || got_addr != base_addr) {
67+ perror (" ERROR: mmap() is not working !!! " );
68+ printf (" got_addr = %p instead of %p\n " , got_addr, base_addr);
69+ assert (false );
70+ }
71+ per = reinterpret_cast <PersistentHeader*>(base_addr);
72+ if (per->id != MAGIC_ID) createFile ();
73+ g_main_size = (max_size - sizeof (PersistentHeader))/2 ;
74+ main_addr = base_addr + sizeof (PersistentHeader);
75+ back_addr = main_addr + g_main_size;
76+ g_main_addr = main_addr;
77+ recover ();
78+ } else {
79+ createFile ();
80+ }
81+ }
82+ }
2783
2884
85+ RomulusLog::~RomulusLog () {
86+ delete[] fc;
87+ // Must do munmap() if we did mmap()
88+ if (dommap) {
89+ // destroy_mspace(ms);
90+ munmap (base_addr, max_size);
91+ close (fd);
92+ }
93+ if (histoflag){
94+ for (int i=0 ;i<300 ;i++){
95+ std::cout<<i<<" :" <<histo[i]<<" \n " ;
96+ }
97+ }
98+ }
99+
100+ void RomulusLog::createFile (){
101+ // File doesn't exist
102+ fd = open (MMAP_FILENAME, O_RDWR|O_CREAT, 0755 );
103+ assert (fd >= 0 );
104+ if (lseek (fd, max_size-1 , SEEK_SET) == -1 ) {
105+ perror (" lseek() error" );
106+ }
107+ if (write (fd, " " , 1 ) == -1 ) {
108+ perror (" write() error" );
109+ }
110+ // mmap() memory range
111+ uint8_t * got_addr = (uint8_t *)mmap (base_addr, max_size, (PROT_READ | PROT_WRITE), MAP_SHARED_VALIDATE | PM_FLAGS, fd, 0 );
112+ if (got_addr == MAP_FAILED || got_addr != base_addr) {
113+ perror (" ERROR: mmap() is not working !!! " );
114+ printf (" got_addr = %p instead of %p\n " , got_addr, base_addr);
115+ assert (false );
116+ }
117+ // No data in persistent memory, initialize
118+ per = new (base_addr) PersistentHeader;
119+ g_main_size = (max_size - sizeof (PersistentHeader))/2 ;
120+ main_addr = base_addr + sizeof (PersistentHeader);
121+ back_addr = main_addr + g_main_size;
122+ g_main_addr = main_addr;
123+ PWB (&per->id );
124+ PWB (&per->state );
125+ // We need to call create_mspace_with_base() from within a transaction so that
126+ // the modifications on 'main' get replicated on 'back'. This means we temporarily
127+ // need to set the 'used_size' to 'main_size' to make sure everything is copied.
128+ begin_transaction ();
129+ // Just to force the copy of the whole main region
130+ per->used_size = g_main_size;
131+ #ifdef USE_ESLOCO
132+ esloco = new EsLoco<persist>(main_addr, g_main_size, false );
133+ per->objects = (void **)esloco->malloc (sizeof (void *)*100 );
134+ #else
135+ per->ms = create_mspace_with_base (main_addr, g_main_size, false );
136+ per->objects = (void **)mspace_malloc (per->ms , sizeof (void *)*100 );
137+ #endif
138+ for (int i = 0 ; i < 100 ; i++) {
139+ per->objects [i] = nullptr ;
140+ add_to_log (&per->objects [i],sizeof (void *));
141+ PWB (&per->objects [i]);
142+ }
143+ end_transaction ();
144+ // The used bytes in the main region
145+ per->used_size = (uint8_t *)(&per->used_size ) - ((uint8_t *)base_addr+sizeof (PersistentHeader))+128 ;
146+ flush_range ((uint8_t *)per,sizeof (PersistentHeader));
147+ PFENCE ();
148+ // Finally, set the id to confirm that the whole initialization process has completed
149+ per->id = MAGIC_ID;
150+ PWB (&per->id );
151+ PSYNC ();
152+ }
153+
154+ void RomulusLog::ns_reset (){
155+ per->id = MAGIC_ID;
156+ PWB (&per->id );
157+ PFENCE ();
158+ std::memset (base_addr,0 ,max_size);
159+
160+ // No data in persistent memory, initialize
161+ per = new (base_addr) PersistentHeader;
162+ g_main_size = (max_size - sizeof (PersistentHeader))/2 ;
163+ main_addr = base_addr + sizeof (PersistentHeader);
164+ back_addr = main_addr + g_main_size;
165+ PWB (&per->id );
166+ PWB (&per->state );
167+ // We need to call create_mspace_with_base() from within a transaction so that
168+ // the modifications on 'main' get replicated on 'back'. This means we temporarily
169+ // need to set the 'used_size' to 'main_size' to make sure everything is copied.
170+ begin_transaction ();
171+ // Just to force the copy of the whole main region
172+ per->used_size = g_main_size;
173+ #ifdef USE_ESLOCO
174+ esloco = new EsLoco<persist>(main_addr, g_main_size, false );
175+ per->objects = (void **)esloco->malloc (sizeof (void *)*100 );
176+ #else
177+ per->ms = create_mspace_with_base (main_addr, g_main_size, false );
178+ per->objects = (void **)mspace_malloc (per->ms , sizeof (void *)*100 );
179+ #endif
180+ for (int i = 0 ; i < 100 ; i++) {
181+ per->objects [i] = nullptr ;
182+ add_to_log (&per->objects [i],sizeof (void *));
183+ PWB (&per->objects [i]);
184+ }
185+ end_transaction ();
186+ // The used bytes in the main region
187+ per->used_size = (uint8_t *)(&per->used_size ) - ((uint8_t *)base_addr+sizeof (PersistentHeader))+128 ;
188+ flush_range ((uint8_t *)per,sizeof (PersistentHeader));
189+ PFENCE ();
190+ // Finally, set the id to confirm that the whole initialization process has completed
191+ per->id = MAGIC_ID;
192+ PWB (&per->id );
193+ PSYNC ();
194+ }
195+
196+ void RomulusLog::reset (){
197+ gRomLog .ns_reset ();
198+ }
199+
200+ /*
201+ * Recovers from an incomplete transaction if needed
202+ */
203+ inline void RomulusLog::recover () {
204+ int lstate = per->state .load (std::memory_order_relaxed);
205+ if (lstate == IDLE) {
206+ return ;
207+ } else if (lstate == COPYING) {
208+ printf (" RomulusLog: Recovery from COPYING...\n " );
209+ copyMainToBack ();
210+ } else if (lstate == MUTATING) {
211+ printf (" RomulusLog: Recovery from MUTATING...\n " );
212+ copyBackToMain ();
213+ } else {
214+ assert (false );
215+ // ERROR: corrupted state
216+ }
217+ PFENCE ();
218+ per->state .store (IDLE, std::memory_order_relaxed);
219+ return ;
220+ }
221+
222+
223+ /*
224+ * Meant to be called from user code when something bad happens and the
225+ * whole transaction needs to be aborted.
226+ * TODO: fix this for nested transactions.
227+ */
228+ inline void RomulusLog::abort_transaction (void ) {
229+ // Check for nested transaction
230+ --tl_nested_write_trans;
231+ if (tl_nested_write_trans != 0 ) return ;
232+ // Apply the log to rollback the modifications
233+ apply_log (back_addr, main_addr);
234+
235+ }
29236
30237}
0 commit comments