usermode/library/mtm/src/mode/pwb-common/tmlog_base.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_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 /* Print debug messages */
00062 #undef _DEBUG_THIS
00063 //#define _DEBUG_THIS
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          * The underlying physical log volatile structure requires to be
00083          * word aligned.
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          * Invariant: If there is a stable region to read from then there is at 
00132          * least one atomic log fragment which corresponds to one logical 
00133          * transaction. 
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                                          * Log fragment corresponds to an aborted transaction.
00146                                          * Ignore it, truncate the log up to here, and retry.
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          * Invariant: If there is a stable region to read from then there is at 
00260          * least one atomic log fragment which corresponds to one logical 
00261          * transaction. 
00262          */
00263 retry:   
00264         if (m_phlog_base_stable_exists(&(tmlog->phlog_base))) {
00265                 /* 
00266                  * Checkpoint the readindex so that we can restore it after we find 
00267                  * the transaction sequence number and be able to recover the 
00268                  * transaction.
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                                         /* Ignore an aborted transaction's log fragment */
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          * Invariant: If there is a stable region to read from then there is at 
00342          * least one atomic log fragment which corresponds to one logical 
00343          * transaction. 
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                                 /* Drop the recovered log fragment */
00352                                 m_phlog_base_truncate_async(set, &tmlog->phlog_base);
00353                                 break;
00354                         } else if (addr == XACT_ABORT_MARKER) {
00355                                 /* 
00356                                  * Recovery shouldn't be passed a log fragment corresponding to
00357                                  * an aborted transaction.
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 }

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