int Store::read(char *buf, uint size) { STORE_ASSERT(m_state == Reading); //printf("%x: Store::read total=%d\n",(int)portable_ftell(m_file),size); do { #if USE_FTELL portable_off_t curPos = portable_ftell(m_file); #else portable_off_t curPos = m_cur; #endif int bytesInBlock = (int)(BLOCK_SIZE - BLOCK_POINTER_SIZE - (curPos & (BLOCK_SIZE - 1))); int bytesLeft = bytesInBlock < (int)size ? (int)size - bytesInBlock : 0; int numBytes = size - bytesLeft; //printf(" Store::read: pos=%x num=%d left=%d\n",(int)curPos,numBytes,bytesLeft); if (numBytes > 0) { //printf("%x: Store::read: %d out of %d bytes\n",(int)portable_ftell(m_file),numBytes,size); if ((int)fread(buf, 1, numBytes, m_file) != numBytes) { fprintf(stderr, "Error reading from store: %s\n", strerror(errno)); exit(1); } m_cur += numBytes; m_reads++; } if (bytesLeft > 0) { portable_off_t newPos; // read offset of the next block #if USE_FTELL STORE_ASSERT(((portable_ftell(m_file) + BLOCK_POINTER_SIZE) & (BLOCK_SIZE - 1)) == 0); #else STORE_ASSERT(((m_cur + BLOCK_POINTER_SIZE) & (BLOCK_SIZE - 1)) == 0); #endif if (fread((char *)&newPos, BLOCK_POINTER_SIZE, 1, m_file) != 1) { fprintf(stderr, "Error reading from store: %s\n", strerror(errno)); exit(1); } //printf("%x: Store::read: continue in next block, %d bytes to go\n",(int)newPos,bytesLeft); //printf(" Store::read: next block=%x\n",(int)newPos); STORE_ASSERT(newPos != 0); STORE_ASSERT((newPos & (BLOCK_SIZE - 1)) == 0); curPos = newPos; // move to next block if (portable_fseek(m_file, curPos, SEEK_SET) == -1) { fprintf(stderr, "Store::read: Error seeking to position %d: %s\n", (int)curPos, strerror(errno)); exit(1); } m_cur = curPos; } size -= numBytes; buf += numBytes; } while (size > 0); return size; }
portable_off_t Store::alloc() { STORE_ASSERT(m_state==Reading); m_state=Writing; portable_off_t pos; if (m_head==0) // allocate new block { //printf("alloc: new block, pos=%lld\n",(long long)m_front); if (portable_fseek(m_file,0,SEEK_END)==-1) // go to end of the file { fprintf(stderr,"Store::alloc: Error seeking to end of file: %s\n",strerror(errno)); exit(1); } #if USE_FTELL pos = portable_ftell(m_file); STORE_ASSERT( (pos & (BLOCK_SIZE-1))==0 ); m_front = pos + BLOCK_SIZE; // move front to end of this block #else m_cur = m_front; pos = m_cur; STORE_ASSERT( (pos & (BLOCK_SIZE-1))==0 ); m_front = pos + BLOCK_SIZE; #endif } else // reuse freed block { //printf("alloc: reuse block: pos=%lld\n",(long long)m_head->pos); Node *node = m_head; pos = node->pos; // point head to next free item m_head = node->next; delete node; // move to start of the block if (portable_fseek(m_file,pos,SEEK_SET)==-1) { fprintf(stderr,"Store::alloc: Error seeking to position %d: %s\n", (int)pos,strerror(errno)); exit(1); } m_cur = pos; STORE_ASSERT( (pos & (BLOCK_SIZE-1))==0 ); } //printf("%x: Store::alloc\n",(int)pos); return pos; }
void Store::end() { STORE_ASSERT(m_state == Writing); #if USE_FTELL portable_off_t curPos = portable_ftell(m_file); #else portable_off_t curPos = m_cur; #endif int bytesInBlock = (int)(BLOCK_SIZE - (curPos & (BLOCK_SIZE - 1))); //printf("%x: Store::end erasing %x bytes\n",(int)curPos&~(BLOCK_SIZE-1),bytesInBlock); //printf("end: bytesInBlock=%x\n",bytesInBlock); // zero out rest of the block int i; for (i = 0; i < bytesInBlock; i++) { fputc(0, m_file); } m_state = Reading; }
bool BufferedFile::seek( const int64 offset, const SeekOrigin origin) { assert(m_file); assert(m_buffer); // Seeking from the end is handled separately, since we don't know the size of the file. if (origin == SeekFromEnd) { if (m_file_mode == ReadMode) invalidate_buffer(); else flush_buffer(); if (portable_fseek(m_file, offset, SEEK_END)) return false; m_file_index = portable_ftell(m_file); } else { int64 target_index; if (origin == SeekFromBeginning) target_index = offset; else { assert(origin == SeekFromCurrent); const int64 current_index = m_file_index + static_cast<int64>(m_buffer_index); target_index = max<int64>(current_index + offset, 0); } if (target_index >= m_file_index && target_index < m_file_index + static_cast<int64>(m_buffer_end)) { // Seek within the I/O buffer. m_buffer_index = static_cast<size_t>(target_index - m_file_index); } else { int64 current_file_index; if (m_file_mode == ReadMode) { current_file_index = m_file_index + static_cast<int64>(m_buffer_end); invalidate_buffer(); } else { current_file_index = m_file_index; flush_buffer(); } if (portable_fseek(m_file, target_index - current_file_index, SEEK_CUR)) return false; m_file_index = portable_ftell(m_file); } } return true; }
int Store::write(const char *buf,uint size) { STORE_ASSERT(m_state==Writing); //printf("%x: Store::write\n",(int)portable_ftell(m_file)); do { #if USE_FTELL portable_off_t curPos = portable_ftell(m_file); #else portable_off_t curPos = m_cur; #endif int bytesInBlock = (int)(BLOCK_SIZE - BLOCK_POINTER_SIZE - (curPos & (BLOCK_SIZE-1))); int bytesLeft = bytesInBlock<(int)size ? (int)size-bytesInBlock : 0; int numBytes = size - bytesLeft; STORE_ASSERT(bytesInBlock>=0); STORE_ASSERT(numBytes<=(int)(BLOCK_SIZE-BLOCK_POINTER_SIZE)); if (numBytes>0) { if ((int)fwrite(buf,1,numBytes,m_file)!=numBytes) { fprintf(stderr,"Error writing: %s\n",strerror(errno)); exit(1); } m_cur+=numBytes; m_writes++; } if (bytesLeft>0) // still more bytes to write { #if USE_FTELL STORE_ASSERT(((portable_ftell(m_file)+BLOCK_POINTER_SIZE)&(BLOCK_SIZE-1))==0); #else STORE_ASSERT(((m_cur+BLOCK_POINTER_SIZE)&(BLOCK_SIZE-1))==0); #endif // allocate new block if (m_head==0) // no free blocks to reuse { //printf("%x: Store::write: new: pos=%x\n",(int)m_front,(int)portable_ftell(m_file)); // write pointer to next block if (fwrite(&m_front,BLOCK_POINTER_SIZE,1,m_file)!=1) { fprintf(stderr,"Error writing to store: %s\n",strerror(errno)); exit(1); } m_cur+=BLOCK_POINTER_SIZE; #if USE_FTELL STORE_ASSERT(portable_ftell(m_file)==(curPos&~(BLOCK_SIZE-1))+BLOCK_SIZE); #else STORE_ASSERT(m_cur==(curPos&~(BLOCK_SIZE-1))+BLOCK_SIZE); #endif // move to next block if (portable_fseek(m_file,0,SEEK_END)==-1) // go to end of the file { fprintf(stderr,"Store::alloc: Error seeking to end of file: %s\n",strerror(errno)); exit(1); } m_cur=m_front; #if USE_FTELL STORE_ASSERT(portable_ftell(m_file)==m_front); #else STORE_ASSERT(m_cur==m_front); #endif // move front to the next of the block m_front+=BLOCK_SIZE; } else // reuse block from the free list { // write pointer to next block if (fwrite(&m_head->pos,BLOCK_POINTER_SIZE,1,m_file)!=1) { fprintf(stderr,"Error writing to store: %s\n",strerror(errno)); exit(1); } Node *node = m_head; portable_off_t pos = node->pos; // point head to next free item m_head = node->next; delete node; // move to start of the block if (portable_fseek(m_file,pos,SEEK_SET)==-1) { fprintf(stderr,"Store::write: Error seeking to position %d: %s\n", (int)pos,strerror(errno)); exit(1); } m_cur = pos; //printf("%x: Store::write: reuse\n",(int)pos); } } size-=numBytes; buf+=numBytes; } while (size>0); return size; }