/trunk/src/kangmodb/chunkList.h
C Header | 227 lines | 157 code | 23 blank | 47 comment | 28 complexity | e5b963839e623ad337c1be9535de4bac MD5 | raw file
Possible License(s): BSD-3-Clause
1/* 2 * chunkList.h 3 * kangmodb 4 * 5 * Created by 강모 김 on 11. 5. 1.. 6 * Copyright 2011 강모소프트. All rights reserved. 7 * 8 */ 9 10#ifndef _KD_CHUNK_LIST_H_ 11#define _KD_CHUNK_LIST_H_ (1) 12 13#include "list.h" 14 15/** @brief The header stored in the root chunk in the chunk list. Root chunk is the first chunk in the list. 16 */ 17typedef struct stgRootChunkHeader 18{ 19 /** @brief Keeps head/tail link of the double linked list. 20 */ 21 list_t chunkList; 22} stgRootChunkHeader; 23 24/** @brief The header stored in chunks in the chunk list. 25 */ 26typedef struct stgChunkHeader 27{ 28 /** @brief Keeps prev/next link of the double linked list. 29 */ 30 list_node_t nodeLinks; 31} stgChunkHeader; 32 33/** @brief Maintain a double linked list that keeps track of multiple memory chunks. 34 * 35 * - stgTransLogBuffer uses stgChunkList to keep multiple log chunks for a transaction. 36 * - stgTable uses stgChunkList to keep multiple memory chunks to keep (key, data) pairs. 37 */ 38class stgChunkList 39{ 40private : 41 /** @brief The first chunk in this chunk list. It has head/tail of the chunk list. 42 */ 43 stgRootChunkHeader * rootChunk_; 44 45 /** @brief The next chunk to iterate. Used by both iterate and reverseIterate. 46 */ 47 mutable void * nextIterationChunk_; 48 49public : 50 51 /** @brief The size of unusable memory at the beginning of added chunk. 52 */ 53 static const int CHUNK_UNUSABLE_SIZE = MAX(sizeof(stgRootChunkHeader), sizeof(stgChunkHeader)); 54 55 stgChunkList() 56 { 57 rootChunk_ = NULL; 58 nextIterationChunk_ = NULL; 59 } 60 ~stgChunkList() 61 { 62 } 63 /** @brief See if the chunk list is empty. 64 */ 65 bool empty() const 66 { 67 // If the root chunk(the first chunk) is NULL, it means the list is empty. 68 return rootChunk_ == NULL; 69 } 70 /** @brief Add a chunk to the chunk list. 71 */ 72 KD_VOID addChunk( const void * chunkAddress ) 73 { 74 KD_TRY 75 { 76 if (rootChunk_ == NULL ) // No root chunk. Set the chunk as the root chunk 77 { 78 rootChunk_ = (stgRootChunkHeader*) chunkAddress; 79 (void) list_init( &rootChunk_->chunkList ); 80 } 81 else 82 { 83 stgChunkHeader * chunkHeader = (stgChunkHeader*) chunkAddress; 84 (void) list_add_tail( &rootChunk_->chunkList, &chunkHeader->nodeLinks); 85 } 86 } 87 KD_CATCH 88 KD_FINALLY 89 KD_END 90 } 91 92 /** @brief Remove a chunk from the list. 93 */ 94 KD_VOID removeChunk( const void * chunkAddress ) 95 { 96 KD_ASSERT( rootChunk_ != NULL ); 97 98 KD_TRY 99 { 100 // If the root chunk is removed, all chunks in the list are removed as well. This is by design. 101 if (chunkAddress == rootChunk_ ) 102 { 103 rootChunk_ = NULL; 104 } 105 else // Not a root chunk, remove from the list 106 { 107 stgChunkHeader * chunkHeader = (stgChunkHeader*) chunkAddress; 108 109 (void) list_remove( &rootChunk_->chunkList, &chunkHeader->nodeLinks ); 110 } 111 } 112 KD_CATCH 113 KD_FINALLY 114 KD_END 115 } 116 117 /** @brief Initialize iterations. 118 */ 119 KD_VOID initIteration() const 120 { 121 KD_TRY 122 { 123 nextIterationChunk_ = rootChunk_; 124 } 125 KD_CATCH 126 KD_FINALLY 127 KD_END 128 } 129 130 /** @brief Iterate a chunk. If no more chunk, *chunkAddress is set to NULL. 131 */ 132 KD_VOID iterate( void ** chunkAddress ) const 133 { 134 KD_DASSERT( chunkAddress != NULL ); 135 136 KD_TRY 137 { 138 if (nextIterationChunk_ == NULL) // End of iteration 139 { 140 *chunkAddress = NULL; 141 } 142 else 143 { 144 *chunkAddress = nextIterationChunk_ ; 145 146 if ( nextIterationChunk_ == rootChunk_ ) 147 { 148 // Root chunk was the first one to iterate chunks. Next chunk to iterate is the one in head in the list. 149 nextIterationChunk_ = rootChunk_->chunkList.head; 150 } 151 else 152 { 153 nextIterationChunk_ = ((stgChunkHeader*) nextIterationChunk_)->nodeLinks.next; 154 } 155 156 if ( nextIterationChunk_ == LIST_NODE_NULL( & rootChunk_->chunkList ) ) // Reached at the end of iteration? 157 { 158 nextIterationChunk_ = NULL; 159 } 160 } 161 } 162 KD_CATCH 163 KD_FINALLY 164 KD_END 165 } 166 167 /** @brief Initialize iterations in reverse order. 168 */ 169 KD_VOID initReverseIteration() const 170 { 171 KD_TRY 172 { 173 if ( rootChunk_ == NULL ) // No chunk is added yet. 174 { 175 nextIterationChunk_ = NULL; // Nothing to iterate. 176 } 177 else 178 { 179 // Start the reverse iteration from the tail of the list. 180 nextIterationChunk_ = rootChunk_->chunkList.tail; 181 } 182 } 183 KD_CATCH 184 KD_FINALLY 185 KD_END 186 } 187 188 /** @brief Iterate a chunk in reverse order. If no more chunk, *chunkAddress is set to NULL. 189 */ 190 KD_VOID reverseIterate( void ** chunkAddress ) const 191 { 192 KD_DASSERT( chunkAddress != NULL ); 193 194 KD_TRY 195 { 196 if (nextIterationChunk_ == NULL) // End of iteration 197 { 198 *chunkAddress = NULL; 199 } 200 else 201 { 202 *chunkAddress = nextIterationChunk_ ; 203 204 if ( nextIterationChunk_ == rootChunk_ ) 205 { 206 // Root chunk was the last one to iterate chunks in reverse order. 207 nextIterationChunk_ = NULL; 208 } 209 else 210 { 211 nextIterationChunk_ = ((stgChunkHeader*) nextIterationChunk_)->nodeLinks.prev; 212 } 213 214 if ( nextIterationChunk_ == LIST_NODE_NULL( & rootChunk_->chunkList ) ) // Reached at the end of the list? 215 { 216 // We need to iterate the root chunk, which is the last one to iterate in reverse order. 217 nextIterationChunk_ = rootChunk_; 218 } 219 } 220 } 221 KD_CATCH 222 KD_FINALLY 223 KD_END 224 } 225}; 226 227#endif /* _KD_CHUNK_LIST_H_ */