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