usermode/library/mcore/src/log/phlog_base.h

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 
00059 #ifndef _PHYSICAL_LOG_BASE_H
00060 #define _PHYSICAL_LOG_BASE_H
00061 
00062 /* System header files */
00063 #include <stdio.h>
00064 #include <stdint.h>
00065 #include <stdbool.h>
00066 /* Mnemosyne common header files */
00067 #include <result.h>
00068 #include <list.h>
00069 #include "../hal/pcm_i.h"
00070 #include "log_i.h"
00071 
00072 
00073 #ifdef __cplusplus
00074 extern "C" {
00075 #endif
00076 
00077 
00078 #define CHUNK_SIZE              64
00079 
00080 
00081 typedef struct m_phlog_base_s      m_phlog_base_t;
00082 typedef struct m_phlog_base_nvmd_s m_phlog_base_nvmd_t;
00083 
00084 struct m_phlog_base_nvmd_s {
00085         pcm_word_t generic_flags;
00086         pcm_word_t head;                         
00087         pcm_word_t tail;     
00088         pcm_word_t reserved4;                
00089 };
00090 
00091 
00092 
00093 
00102 struct m_phlog_base_s {
00103         uint64_t                buffer[CHUNK_SIZE/sizeof(uint64_t)];    
00104         uint64_t                buffer_count;                           
00105         uint64_t                *nvphlog;                               
00106         m_phlog_base_nvmd_t     *nvmd;                                  
00107         uint64_t                head;
00108         uint64_t                tail;
00109         uint64_t                read_index;
00110 
00111         /* statistics */
00112         uint64_t                pad1[8];                                
00113         uint64_t                stat_wait_for_trunc;                    
00114         uint64_t                stat_wait_time_for_trunc;               
00115 };
00116 
00117 
00118 
00125 static inline
00126 void
00127 base_write_buffer2log(pcm_storeset_t *set, m_phlog_base_t *log)
00128 {
00129         /* 
00130          * Modulo arithmetic is implemented using the most efficient equivalent:
00131          * (log->tail + k) % PHYSICAL_LOG_NUM_ENTRIES == (log->tail + k) & (PHYSICAL_LOG_NUM_ENTRIES-1)
00132          */
00133         PCM_SEQSTREAM_STORE_64B_FIRST_WORD(set, (volatile pcm_word_t *) &log->nvphlog[(log->tail+0)], 
00134                                            (pcm_word_t) log->buffer[0]);
00135         PCM_SEQSTREAM_STORE_64B_NEXT_WORD(set, (volatile pcm_word_t *) &log->nvphlog[(log->tail+1)], 
00136                                           (pcm_word_t) log->buffer[1]);
00137         PCM_SEQSTREAM_STORE_64B_NEXT_WORD(set, (volatile pcm_word_t *) &log->nvphlog[(log->tail+2)], 
00138                                           (pcm_word_t) log->buffer[2]);
00139         PCM_SEQSTREAM_STORE_64B_NEXT_WORD(set, (volatile pcm_word_t *) &log->nvphlog[(log->tail+3)], 
00140                                           (pcm_word_t) log->buffer[3]);
00141         PCM_SEQSTREAM_STORE_64B_NEXT_WORD(set, (volatile pcm_word_t *) &log->nvphlog[(log->tail+4)], 
00142                                           (pcm_word_t) log->buffer[4]);
00143         PCM_SEQSTREAM_STORE_64B_NEXT_WORD(set, (volatile pcm_word_t *) &log->nvphlog[(log->tail+5)], 
00144                                           (pcm_word_t) log->buffer[5]);
00145         PCM_SEQSTREAM_STORE_64B_NEXT_WORD(set, (volatile pcm_word_t *) &log->nvphlog[(log->tail+6)], 
00146                                           (pcm_word_t) log->buffer[6]);
00147         PCM_SEQSTREAM_STORE_64B_NEXT_WORD(set, (volatile pcm_word_t *) &log->nvphlog[(log->tail+7)], 
00148                                           (pcm_word_t) log->buffer[7]);
00149         log->buffer_count=0;
00150         log->tail = (log->tail+8) & (PHYSICAL_LOG_NUM_ENTRIES-1);
00151 }
00152 
00153 
00161 static inline
00162 m_result_t
00163 m_phlog_base_write(pcm_storeset_t *set, m_phlog_base_t *log, pcm_word_t value)
00164 {
00165         /* 
00166          * Check there is space in the buffer and in the log before writing the
00167          * new value. This duplicates some code but doesn't require unrolling state
00168          * in case of any error. We could also avoid duplication by putting some
00169          * extra branches but we prefer as few branches as possible in the critical
00170          * path.
00171          */
00172 
00173         /* Will new write fill buffer and require flushing out to log? */
00174         if (log->buffer_count+1 > CHUNK_SIZE/sizeof(pcm_word_t)-1) {
00175                 /* Will log overflow? */
00176                 if (((log->tail + CHUNK_SIZE/sizeof(pcm_word_t)) & (PHYSICAL_LOG_NUM_ENTRIES-1))
00177                     == log->head)
00178                 {
00179                         return M_R_FAILURE;
00180                 } else {
00181                         log->buffer[log->buffer_count] = value; 
00182                         log->buffer_count++;
00183                         base_write_buffer2log(set, log);
00184                 }
00185         } else {
00186                 log->buffer[log->buffer_count] = value;
00187                 log->buffer_count++;
00188         }
00189 
00190         return M_R_SUCCESS;
00191 }
00192 
00193 
00201 static inline
00202 m_result_t
00203 m_phlog_base_flush(pcm_storeset_t *set, m_phlog_base_t *log)
00204 {
00205         if (log->buffer_count > 0) {
00206                 base_write_buffer2log(set, log);
00207         }       
00208         PCM_SEQSTREAM_FLUSH(set);
00209         PCM_NT_STORE(set, (volatile pcm_word_t *) &log->nvmd->tail, 
00210                      (pcm_word_t) log->tail);
00211         PCM_NT_FLUSH(set);
00212 
00213         return M_R_SUCCESS;
00214 }
00215 
00216 
00223 static inline
00224 m_result_t
00225 m_phlog_base_read(m_phlog_base_t *log, uint64_t *valuep)
00226 {
00227         uint64_t value;
00228 
00229         /* Are there any stable data to read? */
00230         if (log->read_index != log->nvmd->tail) {
00231                 value = log->nvphlog[log->read_index];
00232                 log->read_index = (log->read_index + 1) & (PHYSICAL_LOG_NUM_ENTRIES - 1);
00233                 *valuep = value;
00234                 return M_R_SUCCESS;
00235         }
00236         return M_R_FAILURE;
00237 }
00238 
00239 
00246 static inline
00247 bool
00248 m_phlog_base_stable_exists(m_phlog_base_t *log)
00249 {
00250         if (log->read_index != log->nvmd->tail) {
00251                 return true;
00252         }
00253         return false;
00254 }
00255 
00256 
00257 
00263 static inline
00264 void
00265 m_phlog_base_next_chunk(m_phlog_base_t *log)
00266 {
00267         uint64_t read_index; 
00268 
00269         read_index = log->read_index & ~(CHUNK_SIZE/sizeof(pcm_word_t) - 1);
00270         /* 
00271          * If current log->read_index points to the beginning of a chunk
00272          * then we are already in the next chunk so we don't need to advance.
00273          */
00274         if (read_index != log->read_index) {
00275                 log->read_index = (read_index + CHUNK_SIZE/sizeof(pcm_word_t)) & (PHYSICAL_LOG_NUM_ENTRIES-1); 
00276         }
00277 }
00278 
00279 
00286 static inline
00287 m_result_t
00288 m_phlog_base_checkpoint_readindex(m_phlog_base_t *log, uint64_t *readindex)
00289 {
00290         *readindex = log->read_index;
00291 
00292         return M_R_SUCCESS;
00293 }
00294 
00295 
00302 static inline
00303 void
00304 m_phlog_base_restore_readindex(m_phlog_base_t *log, uint64_t readindex)
00305 {
00306         log->read_index = readindex;
00307 }
00308 
00309 
00310 static inline
00311 m_result_t
00312 m_phlog_base_truncate_sync(pcm_storeset_t *set, m_phlog_base_t *phlog) 
00313 {
00314         phlog->head = phlog->tail;
00315 
00316         PCM_NT_STORE(set, (volatile pcm_word_t *) &phlog->nvmd->head, 
00317                      (pcm_word_t) phlog->head);
00318         PCM_NT_FLUSH(set);
00319         
00320         return M_R_SUCCESS;
00321 }
00322 
00323 
00324 m_result_t m_phlog_base_format (pcm_storeset_t *set, m_phlog_base_nvmd_t *nvmd, pcm_word_t *nvphlog, int type);
00325 m_result_t m_phlog_base_alloc (m_phlog_base_t **phlog_basep);
00326 m_result_t m_phlog_base_init (m_phlog_base_t *phlog, m_phlog_base_nvmd_t *nvmd, pcm_word_t *nvphlog);
00327 m_result_t m_phlog_base_check_consistency(m_phlog_base_nvmd_t *nvmd, pcm_word_t *nvphlog, uint64_t *stable_tail);
00328 m_result_t m_phlog_base_truncate_async(pcm_storeset_t *set, m_phlog_base_t *phlog);
00329 
00330 
00331 #ifdef __cplusplus
00332 }
00333 #endif
00334 
00335 #endif /* _PHYSICAL_LOG_BASE_H */

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