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
00041 #include <stdio.h>
00042 #include <assert.h>
00043 #include <mnemosyne.h>
00044 #include <pcm.h>
00045 #include <cuckoo_hash/PointerHashInline.h>
00046 #include <debug.h>
00047 #include "tmlog_tornbit.h"
00048
00049 m_log_ops_t tmlog_tornbit_ops = {
00050 m_tmlog_tornbit_alloc,
00051 m_tmlog_tornbit_init,
00052 m_tmlog_tornbit_truncation_init,
00053 m_tmlog_tornbit_truncation_prepare_next,
00054 m_tmlog_tornbit_truncation_do,
00055 m_tmlog_tornbit_recovery_init,
00056 m_tmlog_tornbit_recovery_prepare_next,
00057 m_tmlog_tornbit_recovery_do,
00058 m_tmlog_tornbit_report_stats,
00059 };
00060
00061 #define FLUSH_CACHELINE_ONCE
00062
00063
00064 #undef _DEBUG_THIS
00065
00066
00067
00068 #define _DEBUG_PRINT_TMLOG(tmlog) \
00069 printf("nvmd : %p\n", tmlog->phlog_tornbit.nvmd); \
00070 printf("nvphlog : %p\n", tmlog->phlog_tornbit.nvphlog); \
00071 printf("stable_tail: %lu\n", tmlog->phlog_tornbit.stable_tail); \
00072 printf("tail : %lu\n", tmlog->phlog_tornbit.tail); \
00073 printf("head : %lu\n", tmlog->phlog_tornbit.head); \
00074 printf("read_index : %lu\n", tmlog->phlog_tornbit.read_index);
00075
00076 void PointerHash_removeKey_noshrink(PointerHash *self, void *k)
00077 {
00078 PointerHashRecord *r;
00079
00080 r = PointerHash_record1_(self, k);
00081 if(r->k == k)
00082 {
00083 r->k = 0x0;
00084 r->v = 0x0;
00085 self->keyCount --;
00086 return;
00087 }
00088
00089 r = PointerHash_record2_(self, k);
00090 if(r->k == k)
00091 {
00092 r->k = 0x0;
00093 r->v = 0x0;
00094 self->keyCount --;
00095 return;
00096 }
00097 }
00098
00099
00100 m_result_t
00101 m_tmlog_tornbit_alloc(m_log_dsc_t *log_dsc)
00102 {
00103 m_tmlog_tornbit_t *tmlog_tornbit;
00104
00105 if (posix_memalign((void **) &tmlog_tornbit, sizeof(uint64_t), sizeof(m_tmlog_tornbit_t)) != 0)
00106 {
00107 return M_R_FAILURE;
00108 }
00109
00110
00111
00112
00113 assert((( (uintptr_t) &tmlog_tornbit->phlog_tornbit) & (sizeof(uint64_t)-1)) == 0);
00114 tmlog_tornbit->flush_set = (tornbit_flush_set_t *) PointerHash_new();
00115 log_dsc->log = (m_log_t *) tmlog_tornbit;
00116
00117 return M_R_SUCCESS;
00118 }
00119
00120
00121 m_result_t
00122 m_tmlog_tornbit_init(pcm_storeset_t *set, m_log_t *log, m_log_dsc_t *log_dsc)
00123 {
00124 m_tmlog_tornbit_t *tmlog_tornbit = (m_tmlog_tornbit_t *) log;
00125 m_phlog_tornbit_t *phlog_tornbit = &(tmlog_tornbit->phlog_tornbit);
00126
00127 m_phlog_tornbit_format(set,
00128 (m_phlog_tornbit_nvmd_t *) log_dsc->nvmd,
00129 log_dsc->nvphlog,
00130 LF_TYPE_TM_TORNBIT);
00131 m_phlog_tornbit_init(phlog_tornbit,
00132 (m_phlog_tornbit_nvmd_t *) log_dsc->nvmd,
00133 log_dsc->nvphlog);
00134
00135 return M_R_SUCCESS;
00136 }
00137
00138
00139 static inline
00140 m_result_t
00141 truncation_prepare(pcm_storeset_t *set, m_log_dsc_t *log_dsc)
00142 {
00143 m_tmlog_tornbit_t *tmlog = (m_tmlog_tornbit_t *) log_dsc->log;
00144 pcm_word_t value;
00145 uint64_t sqn = INV_LOG_ORDER;
00146 uintptr_t addr;
00147 pcm_word_t mask;
00148 uintptr_t block_addr;
00149 int val;
00150
00151 #ifdef _DEBUG_THIS
00152 printf("prepare_truncate: log_dsc = %p\n", log_dsc);
00153 _DEBUG_PRINT_TMLOG(tmlog)
00154 #endif
00155
00156
00157
00158
00159
00160
00161 retry:
00162 if (m_phlog_tornbit_stable_exists(&(tmlog->phlog_tornbit))) {
00163 while(1) {
00164 if (m_phlog_tornbit_read(&(tmlog->phlog_tornbit), &addr) == M_R_SUCCESS) {
00165 if (addr == XACT_COMMIT_MARKER) {
00166 assert(m_phlog_tornbit_read(&(tmlog->phlog_tornbit), &sqn) == M_R_SUCCESS);
00167 m_phlog_tornbit_next_chunk(&tmlog->phlog_tornbit);
00168 break;
00169 } else if (addr == XACT_ABORT_MARKER) {
00170
00171
00172
00173
00174
00175 goto retry;
00176 } else {
00177 assert(m_phlog_tornbit_read(&(tmlog->phlog_tornbit), &value) == M_R_SUCCESS);
00178 assert(m_phlog_tornbit_read(&(tmlog->phlog_tornbit), &mask) == M_R_SUCCESS);
00179 #ifdef _DEBUG_THIS
00180 printf("addr = 0x%lX\n", addr);
00181 printf("value = 0x%lX\n", value);
00182 printf("mask = 0x%lX\n", mask);
00183 #endif
00184 block_addr = (uintptr_t) BLOCK_ADDR(addr);
00185
00186 #ifdef FLUSH_CACHELINE_ONCE
00187 if (!PointerHash_at_((PointerHash *) tmlog->flush_set, (void *) block_addr)) {
00188 PointerHash_at_put_((PointerHash *) tmlog->flush_set,
00189 (void *) block_addr,
00190 (void *) 1);
00191 }
00192 #else
00193 PCM_WB_FLUSH(set, (volatile pcm_word_t *) block_addr);
00194 #endif
00195 }
00196 } else {
00197 M_INTERNALERROR("Invariant violation: there must be at least one atomic log fragment.");
00198 }
00199 }
00200 log_dsc->logorder = sqn;
00201 } else {
00202 log_dsc->logorder = sqn;
00203 }
00204
00205 return M_R_SUCCESS;
00206 }
00207
00208
00209 m_result_t
00210 m_tmlog_tornbit_truncation_init(pcm_storeset_t *set, m_log_dsc_t *log_dsc)
00211 {
00212 return truncation_prepare(set, log_dsc);
00213 }
00214
00215
00216 m_result_t
00217 m_tmlog_tornbit_truncation_prepare_next(pcm_storeset_t *set, m_log_dsc_t *log_dsc)
00218 {
00219 return truncation_prepare(set, log_dsc);
00220 }
00221
00222
00223 m_result_t
00224 m_tmlog_tornbit_truncation_do(pcm_storeset_t *set, m_log_dsc_t *log_dsc)
00225 {
00226 int i;
00227 m_tmlog_tornbit_t *tmlog = (m_tmlog_tornbit_t *) log_dsc->log;
00228 uintptr_t block_addr;
00229
00230 #ifdef _DEBUG_THIS
00231 printf("m_tmlog_tornbit_truncation_do: START\n");
00232 _DEBUG_PRINT_TMLOG(tmlog)
00233 #endif
00234
00235 #ifdef FLUSH_CACHELINE_ONCE
00236 for(i = 0; i < ((PointerHash *) tmlog->flush_set)->size; i++) {
00237 PointerHashRecord *r = PointerHashRecords_recordAt_(((PointerHash *) tmlog->flush_set)->records, i);
00238 if (block_addr = (uintptr_t) r->k) {
00239
00240 PointerHash_removeKey_((PointerHash *) tmlog->flush_set, (void *) block_addr);
00241 PCM_WB_FLUSH(set, (volatile pcm_word_t *) block_addr);
00242 }
00243 }
00244 #endif
00245 m_phlog_tornbit_truncate_async(set, &tmlog->phlog_tornbit);
00246
00247 #ifdef _DEBUG_THIS
00248 printf("m_tmlog_tornbit_truncation_do: DONE\n");
00249 _DEBUG_PRINT_TMLOG(tmlog)
00250 #endif
00251
00252 return M_R_SUCCESS;
00253 }
00254
00255 static inline
00256 m_result_t
00257 recovery_prepare_next(pcm_storeset_t *set, m_log_dsc_t *log_dsc)
00258 {
00259 m_tmlog_tornbit_t *tmlog = (m_tmlog_tornbit_t *) log_dsc->log;
00260 pcm_word_t value;
00261 uint64_t sqn = INV_LOG_ORDER;
00262 uintptr_t addr;
00263 pcm_word_t mask;
00264 uintptr_t block_addr;
00265 int val;
00266 uint64_t readindex_checkpoint;
00267
00268 #ifdef _DEBUG_THIS
00269 printf("recovery_prepare_next: log_dsc = %p\n", log_dsc);
00270 _DEBUG_PRINT_TMLOG(tmlog)
00271 #endif
00272
00273
00274
00275
00276
00277
00278 retry:
00279 if (m_phlog_tornbit_stable_exists(&(tmlog->phlog_tornbit))) {
00280
00281
00282
00283
00284
00285 assert(m_phlog_tornbit_checkpoint_readindex(&(tmlog->phlog_tornbit), &readindex_checkpoint) == M_R_SUCCESS);
00286 while(1) {
00287 if (m_phlog_tornbit_read(&(tmlog->phlog_tornbit), &addr) == M_R_SUCCESS) {
00288 if (addr == XACT_COMMIT_MARKER) {
00289 assert(m_phlog_tornbit_read(&(tmlog->phlog_tornbit), &sqn) == M_R_SUCCESS);
00290 m_phlog_tornbit_restore_readindex(&(tmlog->phlog_tornbit), readindex_checkpoint);
00291 break;
00292 } else if (addr == XACT_ABORT_MARKER) {
00293 assert(m_phlog_tornbit_read(&(tmlog->phlog_tornbit), &sqn) == M_R_SUCCESS);
00294 m_phlog_tornbit_next_chunk(&tmlog->phlog_tornbit);
00295
00296 m_phlog_tornbit_truncate_async(set, &tmlog->phlog_tornbit);
00297 sqn = INV_LOG_ORDER;
00298 goto retry;
00299 } else {
00300 assert(m_phlog_tornbit_read(&(tmlog->phlog_tornbit), &value) == M_R_SUCCESS);
00301 assert(m_phlog_tornbit_read(&(tmlog->phlog_tornbit), &mask) == M_R_SUCCESS);
00302 }
00303 } else {
00304 M_INTERNALERROR("Invariant violation: there must be at least one atomic log fragment.");
00305 }
00306 }
00307 log_dsc->logorder = sqn;
00308 } else {
00309 log_dsc->logorder = sqn;
00310 }
00311
00312 return M_R_SUCCESS;
00313 }
00314
00315
00316 m_result_t
00317 m_tmlog_tornbit_recovery_init(pcm_storeset_t *set, m_log_dsc_t *log_dsc)
00318 {
00319 m_tmlog_tornbit_t *tmlog = (m_tmlog_tornbit_t *) log_dsc->log;
00320
00321 m_phlog_tornbit_init(&tmlog->phlog_tornbit,
00322 (m_phlog_tornbit_nvmd_t *) log_dsc->nvmd,
00323 log_dsc->nvphlog);
00324
00325 m_phlog_tornbit_check_consistency((m_phlog_tornbit_nvmd_t *) log_dsc->nvmd,
00326 log_dsc->nvphlog,
00327 &(tmlog->phlog_tornbit.stable_tail));
00328 recovery_prepare_next(set, log_dsc);
00329
00330 return M_R_SUCCESS;
00331 }
00332
00333
00334 m_result_t
00335 m_tmlog_tornbit_recovery_prepare_next(pcm_storeset_t *set, m_log_dsc_t *log_dsc)
00336 {
00337 return recovery_prepare_next(set, log_dsc);
00338 }
00339
00340
00341 m_result_t
00342 m_tmlog_tornbit_recovery_do(pcm_storeset_t *set, m_log_dsc_t *log_dsc)
00343 {
00344 m_tmlog_tornbit_t *tmlog = (m_tmlog_tornbit_t *) log_dsc->log;
00345 pcm_word_t value;
00346 uint64_t sqn = INV_LOG_ORDER;
00347 uintptr_t addr;
00348 pcm_word_t mask;
00349 uintptr_t block_addr;
00350 int val;
00351 uint64_t readindex_checkpoint;
00352
00353 #ifdef _DEBUG_THIS
00354 printf("m_tmlog_tornbit_recovery_do: %lu\n", log_dsc->logorder);
00355 _DEBUG_PRINT_TMLOG(tmlog)
00356 #endif
00357
00358
00359
00360
00361
00362
00363 assert (m_phlog_tornbit_stable_exists(&(tmlog->phlog_tornbit)));
00364
00365 #ifdef _DEBUG_THIS
00366 printf("tmlog->phlog_tornbit.head = %llu\n", tmlog->phlog_tornbit.head);
00367 printf("tmlog->phlog_tornbit.stable_tail = %llu\n", tmlog->phlog_tornbit.stable_tail);
00368 printf("tmlog->phlog_tornbit.read_index = %llu\n", tmlog->phlog_tornbit.read_index);
00369 #endif
00370 while(1) {
00371 if (m_phlog_tornbit_read(&(tmlog->phlog_tornbit), &addr) == M_R_SUCCESS) {
00372 if (addr == XACT_COMMIT_MARKER) {
00373 assert(m_phlog_tornbit_read(&(tmlog->phlog_tornbit), &sqn) == M_R_SUCCESS);
00374 m_phlog_tornbit_next_chunk(&tmlog->phlog_tornbit);
00375
00376 m_phlog_tornbit_truncate_async(set, &tmlog->phlog_tornbit);
00377 break;
00378 } else if (addr == XACT_ABORT_MARKER) {
00379
00380
00381
00382
00383 M_INTERNALERROR("Trying to recover an aborted transaction!\n");
00384 } else {
00385 assert(m_phlog_tornbit_read(&(tmlog->phlog_tornbit), &value) == M_R_SUCCESS);
00386 assert(m_phlog_tornbit_read(&(tmlog->phlog_tornbit), &mask) == M_R_SUCCESS);
00387 if (mask!=0) {
00388 PCM_WB_STORE_ALIGNED_MASKED(set, (volatile pcm_word_t *) addr, value, mask);
00389 PCM_WB_FLUSH(set, (volatile pcm_word_t *) addr);
00390 }
00391 }
00392 } else {
00393 M_INTERNALERROR("Invariant violation: there must be at least one atomic log fragment.");
00394 }
00395 }
00396
00397 return M_R_SUCCESS;
00398 }
00399
00400
00401 m_result_t
00402 m_tmlog_tornbit_report_stats(m_log_dsc_t *log_dsc)
00403 {
00404 m_tmlog_tornbit_t *tmlog = (m_tmlog_tornbit_t *) log_dsc->log;
00405 m_phlog_tornbit_t *phlog = &(tmlog->phlog_tornbit);
00406
00407 printf("PRINT TORNBIT STATS\n");
00408 printf("wait_for_trunc : %llu\n", phlog->stat_wait_for_trunc);
00409 if (phlog->stat_wait_for_trunc > 0) {
00410 printf("AVG(stat_wait_time_for_trunc): %llu\n", phlog->stat_wait_time_for_trunc / phlog->stat_wait_for_trunc);
00411 }
00412 }