4 #define FILE_CACHED_DEBUG_LOG 0 6 class file_cached_impl_v2 :
public file_cached {
8 enum {minBlockSize = 4096};
9 enum {maxSkipSize = 128*1024};
10 file_cached_impl_v2(
size_t maxBlockSize) : m_maxBlockSize(maxBlockSize) {
13 size_t get_cache_block_size() {
return m_maxBlockSize;}
14 void suggest_grow_cache(
size_t suggestSize) {
15 if (m_maxBlockSize < suggestSize) m_maxBlockSize = suggestSize;
20 m_can_seek = m_base->can_seek();
28 m_position_base = m_base->get_position(p_abort);
33 m_size = m_base->get_size(p_abort);
40 if (p_bytes > maxSkipSize) {
43 const t_filesize position = get_position(p_abort);
45 seek(position + toskip,p_abort);
49 return skip_( p_bytes, p_abort );
52 #if FILE_CACHED_DEBUG_LOG 53 FB2K_DebugLog() <<
"Skipping bytes: " << p_bytes;
57 size_t inBuffer = this->bufferRemaining();
58 size_t delta = (size_t) pfc::min_t<t_filesize>(inBuffer, todo);
59 m_bufferReadPtr += delta;
64 this->m_bufferState = 0;
65 this->m_bufferReadPtr = 0;
66 baseSeek(m_position,p_abort);
67 m_readSize = pfc::min_t<size_t>(m_readSize << 1, this->m_maxBlockSize);
68 if (m_readSize < minBlockSize) m_readSize = minBlockSize;
69 #if FILE_CACHED_DEBUG_LOG 70 FB2K_DebugLog() <<
"Growing read size: " << m_readSize;
72 m_buffer.grow_size(m_readSize);
73 m_bufferState = m_base->read(m_buffer.get_ptr(), m_readSize, p_abort);
74 if (m_bufferState == 0)
break;
75 m_position_base += m_bufferState;
78 return p_bytes - todo;
82 #if FILE_CACHED_DEBUG_LOG 83 FB2K_DebugLog() <<
"Reading bytes: " << p_bytes;
86 size_t todo = p_bytes;
88 size_t inBuffer = this->bufferRemaining();
89 size_t delta = pfc::min_t<size_t>(inBuffer, todo);
90 memcpy(outptr, this->m_buffer.get_ptr() + m_bufferReadPtr, delta);
91 m_bufferReadPtr += delta;
97 this->m_bufferState = 0;
98 this->m_bufferReadPtr = 0;
99 baseSeek(m_position,p_abort);
100 m_readSize = pfc::min_t<size_t>(m_readSize << 1, this->m_maxBlockSize);
101 if (m_readSize < minBlockSize) m_readSize = minBlockSize;
102 #if FILE_CACHED_DEBUG_LOG 103 FB2K_DebugLog() <<
"Growing read size: " << m_readSize;
105 m_buffer.grow_size(m_readSize);
106 m_bufferState = m_base->read(m_buffer.get_ptr(), m_readSize, p_abort);
107 if (m_bufferState == 0)
break;
108 m_position_base += m_bufferState;
111 return p_bytes - todo;
115 #if FILE_CACHED_DEBUG_LOG 116 FB2K_DebugLog() <<
"Writing bytes: " << p_bytes;
119 baseSeek(m_position,p_abort);
120 m_base->write(p_buffer,p_bytes,p_abort);
121 m_position_base = m_position = m_position + p_bytes;
122 if (m_size < m_position) m_size = m_position;
136 baseSeek(m_position,p_abort);
137 m_base->set_eof(p_abort);
141 #if FILE_CACHED_DEBUG_LOG 142 FB2K_DebugLog() <<
"Seeking: " << p_position;
145 if (!m_can_seek)
throw exception_io_object_not_seekable();
146 if (p_position > m_size)
throw exception_io_seek_out_of_range();
147 int64_t delta = p_position - m_position;
150 if (delta >= 0 && delta <= this->minBlockSize) {
151 #if FILE_CACHED_DEBUG_LOG 152 FB2K_DebugLog() <<
"Skip-seeking: " << p_position;
154 t_filesize skipped = this->skip_( delta, p_abort );
155 PFC_ASSERT( skipped == delta ); (void) skipped;
159 m_position = p_position;
161 if ((delta >= 0 && (uint64_t) delta <= bufferRemaining()) || (delta < 0 && (uint64_t)(-delta) <= m_bufferReadPtr)) {
162 #if FILE_CACHED_DEBUG_LOG 163 FB2K_DebugLog() <<
"Quick-seeking: " << p_position;
165 m_bufferReadPtr += (ptrdiff_t)delta;
167 #if FILE_CACHED_DEBUG_LOG 168 FB2K_DebugLog() <<
"Slow-seeking: " << p_position;
170 this->flush_buffer();
174 if (this->m_can_seek) {
177 this->m_base->reopen( p_abort );
178 this->_reinit( p_abort );
181 bool can_seek() {
return m_can_seek;}
182 bool get_content_type(
pfc::string_base & out) {
return m_base->get_content_type(out);}
183 void on_idle(
abort_callback & p_abort) {p_abort.check();m_base->on_idle(p_abort);}
185 bool is_remote() {
return m_base->is_remote();}
188 m_base->resize(p_size,p_abort);
190 if (m_position > m_size) m_position = m_size;
191 if (m_position_base > m_size) m_position_base = m_size;
194 size_t bufferRemaining()
const {
return m_bufferState - m_bufferReadPtr;}
196 if (p_target != m_position_base) {
197 m_base->seek(p_target,p_abort);
198 m_position_base = p_target;
202 void flush_buffer() {
203 m_bufferState = m_bufferReadPtr = 0;
210 size_t m_bufferState, m_bufferReadPtr;
212 size_t m_maxBlockSize;
216 class file_cached_impl :
public file_cached {
218 file_cached_impl(
t_size blocksize) {
221 size_t get_cache_block_size() {
return m_buffer.get_size();}
222 void suggest_grow_cache(
size_t suggestSize) {}
225 m_can_seek = m_base->can_seek();
233 m_position_base = m_base->get_position(p_abort);
238 m_size = m_base->get_size(p_abort);
247 while(done < p_bytes && m_position < m_size) {
250 if (m_position >= m_buffer_position && m_position < m_buffer_position + m_buffer_status) {
251 t_size delta = pfc::min_t<t_size>((
t_size)(m_buffer_position + m_buffer_status - m_position),p_bytes - done);
252 t_size bufptr = (
t_size)(m_position - m_buffer_position);
253 memcpy(outptr+done,m_buffer.get_ptr()+bufptr,delta);
256 if (m_buffer_status != m_buffer.get_size() && done < p_bytes)
break;
258 m_buffer_position = m_position - m_position % m_buffer.get_size();
259 baseSeek(m_buffer_position,p_abort);
261 m_buffer_status = m_base->read(m_buffer.get_ptr(),m_buffer.get_size(),p_abort);
262 m_position_base += m_buffer_status;
264 if (m_buffer_status <= (
t_size)(m_position - m_buffer_position))
break;
273 baseSeek(m_position,p_abort);
274 m_base->write(p_buffer,p_bytes,p_abort);
275 m_position_base = m_position = m_position + p_bytes;
276 if (m_size < m_position) m_size = m_position;
290 baseSeek(m_position,p_abort);
291 m_base->set_eof(p_abort);
296 if (!m_can_seek)
throw exception_io_object_not_seekable();
297 if (p_position > m_size)
throw exception_io_seek_out_of_range();
298 m_position = p_position;
301 if (this->m_can_seek) {
304 this->m_base->reopen( p_abort );
305 this->_reinit( p_abort );
308 bool can_seek() {
return m_can_seek;}
309 bool get_content_type(
pfc::string_base & out) {
return m_base->get_content_type(out);}
310 void on_idle(
abort_callback & p_abort) {p_abort.check();m_base->on_idle(p_abort);}
312 bool is_remote() {
return m_base->is_remote();}
315 m_base->resize(p_size,p_abort);
317 if (m_position > m_size) m_position = m_size;
318 if (m_position_base > m_size) m_position_base = m_size;
322 if (p_target != m_position_base) {
323 m_base->seek(p_target,p_abort);
324 m_position_base = p_target;
328 void flush_buffer() {
330 m_buffer_position = 0;
345 if (p_base->is_in_memory()) {
351 if (p_base->service_query_t(c)) {
352 c->suggest_grow_cache(blockSize);
358 temp->initialize(p_base,p_abort);
363 p_out = g_create(p_base, p_abort, blockSize);
366 void file_cached::g_decodeInitCache(file::ptr & theFile,
abort_callback & abort,
size_t blockSize) {
367 if (theFile->is_remote() || !theFile->can_seek())
return;
369 g_create(theFile, theFile, abort, blockSize);
void read(const service_ptr_t< file > &p_file, abort_callback &p_abort, pfc::string_base &p_out, bool &is_utf8)
t_filesize get_size(HANDLE p_handle)
Template implementing reference-counting features of service_base. Intended for dynamic instantiation...
This class is used to signal underlying worker code whether user has decided to abort a potentially t...
T min_t(const T &item1, const T &item2)
void seek(HANDLE p_handle, t_sfilesize p_position, file::t_seek_mode p_mode)
static const t_filesize filesize_invalid
Invalid/unknown file size constant. Also see: t_filesize.
void set_size(t_size p_size)
void write(const service_ptr_t< file > &p_file, abort_callback &p_abort, const char *p_string, bool is_utf8)
t_uint64 t_filetimestamp
Type used for file timestamp related variables. 64-bit value representing the number of 100-nanosecon...
t_uint64 t_filesize
Type used for file size related variables.