usermode/library/mtm/src/mode/pwb-common/tmlog_tornbit.c

Go to the documentation of this file.
00001 /*
00002     Copyright (C) 2011 Computer Sciences Department, 
00003     University of Wisconsin -- Madison
00004 
00005     ----------------------------------------------------------------------
00006 
00007     This file is part of Mnemosyne: Lightweight Persistent Memory, 
00008     originally developed at the University of Wisconsin -- Madison.
00009 
00010     Mnemosyne was originally developed primarily by Haris Volos
00011     with contributions from Andres Jaan Tack.
00012 
00013     ----------------------------------------------------------------------
00014 
00015     Mnemosyne is free software; you can redistribute it and/or
00016     modify it under the terms of the GNU General Public License
00017     as published by the Free Software Foundation, version 2
00018     of the License.
00019  
00020     Mnemosyne is distributed in the hope that it will be useful,
00021     but WITHOUT ANY WARRANTY; without even the implied warranty of
00022     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023     GNU General Public License for more details.
00024 
00025     You should have received a copy of the GNU General Public License
00026     along with this program; if not, write to the Free Software
00027     Foundation, Inc., 51 Franklin Street, Fifth Floor, 
00028     Boston, MA  02110-1301, USA.
00029 
00030 ### END HEADER ###
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 /* Print debug messages */
00064 #undef _DEBUG_THIS
00065 //#define _DEBUG_THIS
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          * The underlying physical log volatile structure requires to be
00111          * word aligned.
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          * Invariant: If there is a stable region to read from then there is at 
00158          * least one atomic log fragment which corresponds to one logical 
00159          * transaction. 
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                                          * Log fragment corresponds to an aborted transaction.
00172                                          * Ignore it, truncate the log up to here, and retry.
00173                                          */
00174                                         //FIXME: truncate the log up to here
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                         //PointerHash_removeKey_noshrink((PointerHash *) tmlog->flush_set, (void *) block_addr);
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          * Invariant: If there is a stable region to read from then there is at 
00275          * least one atomic log fragment which corresponds to one logical 
00276          * transaction. 
00277          */
00278 retry:   
00279         if (m_phlog_tornbit_stable_exists(&(tmlog->phlog_tornbit))) {
00280                 /* 
00281                  * Checkpoint the readindex so that we can restore it after we find 
00282                  * the transaction sequence number and be able to recover the 
00283                  * transaction.
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                                         /* Ignore an aborted transaction's log fragment */
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          * Invariant: If there is a stable region to read from then there is at 
00360          * least one atomic log fragment which corresponds to one logical 
00361          * transaction. 
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                                 /* Drop the recovered log fragment */
00376                                 m_phlog_tornbit_truncate_async(set, &tmlog->phlog_tornbit);
00377                                 break;
00378                         } else if (addr == XACT_ABORT_MARKER) {
00379                                 /* 
00380                                  * Recovery shouldn't be passed a log fragment corresponding to
00381                                  * an aborted transaction.
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 }

Generated on Sat Apr 23 11:43:36 2011 for Mnemosyne by  doxygen 1.4.7