1 /*********************************************************************/ 2 // dar - disk archive - a backup/restoration program 3 // Copyright (C) 2002-2052 Denis Corbin 4 // 5 // This program is free software; you can redistribute it and/or 6 // modify it under the terms of the GNU General Public License 7 // as published by the Free Software Foundation; either version 2 8 // of the License, or (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with this program; if not, write to the Free Software 17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 // 19 // to contact the author : http://dar.linux.free.fr/email.html 20 /*********************************************************************/ 21 22 /// \file cache.hpp 23 /// \brief contains the cache class 24 /// \ingroup Private 25 26 #ifndef CACHE_HPP 27 #define CACHE_HPP 28 29 #include "../my_config.h" 30 #include "infinint.hpp" 31 #include "generic_file.hpp" 32 33 namespace libdar 34 { 35 36 /// \ingroup Private 37 /// @} 38 39 /// the cache class implements a fixed length read/write caching mechanism 40 /// 41 /// it is intended to reduce context switches when no compression is used 42 /// and when reading or writing catalogue through a pipe. The catalogue 43 /// read and write is done by calling dump/constructor methods of the many 44 /// objects that a catalogue contains. This makes a lot of small reads or 45 /// writes, which make very poor performances when used over the network 46 /// through a pipe to ssh. When compression is used, the problem disapears 47 /// as the compression engine gather these many small reads or writes into 48 /// much bigger ones. This in only when there is no compression or encryption 49 /// that this class is useful (and used). 50 /// Another target of class cache is to provide limited skippability when 51 /// data is read of written to pipe (which do not have any skippability) 52 class cache : public generic_file 53 { 54 public: 55 cache(generic_file & hidden, //< is the file to cache, it is never deleted by the cache object, 56 bool shift_mode, //< if true, when all cached data has been read, half of the data is flushed from the cache, the other half is shifted and new data take place to fill the cache. This is necessary for sequential reading, but has some CPU overhead. 57 U_I size = 102400); //< is the (fixed) size of the cache cache(const cache & ref)58 cache(const cache & ref) : generic_file(ref.get_mode()) { throw SRC_BUG; }; operator =(const cache & ref)59 const cache & operator = (const cache & ref) { throw SRC_BUG; }; 60 ~cache(); change_to_read_write()61 void change_to_read_write() { if(get_mode() == gf_read_only) throw SRC_BUG; set_mode(gf_read_write); }; 62 63 // inherited from generic_file 64 65 bool skippable(skippability direction, const infinint & amount); 66 bool skip(const infinint & pos); 67 bool skip_to_eof(); 68 bool skip_relative(S_I x); get_position() const69 infinint get_position() const { return buffer_offset + next; }; 70 71 protected: 72 // inherited from generic_file inherited_read_ahead(const infinint & amount)73 void inherited_read_ahead(const infinint & amount) { ref->read_ahead(amount - available_in_cache(generic_file::skip_forward)); }; 74 U_I inherited_read(char *a, U_I size); 75 void inherited_write(const char *a, U_I size); inherited_sync_write()76 void inherited_sync_write() { flush_write(); }; inherited_flush_read()77 void inherited_flush_read() { flush_write(); clear_buffer(); }; inherited_terminate()78 void inherited_terminate() { flush_write(); }; 79 80 private: 81 generic_file *ref; //< underlying file, (not owned by "this', not to be delete by "this") 82 char *buffer; //< data in transit 83 U_I size; //< allocated size 84 U_I next; //< next to read or next place to write to 85 U_I last; //< last valid data in the cache. we have: next <= last < size 86 U_I first_to_write; //< position of the first byte that need to be written. if greater than last, no byte need writing 87 infinint buffer_offset; //< position of the first byte in buffer 88 bool shifted_mode; //< whether to half flush and shift or totally flush data 89 need_flush_write() const90 bool need_flush_write() const { return first_to_write < last; }; 91 void alloc_buffer(size_t x_size); //< allocate x_size byte in buffer field and set size accordingly 92 void release_buffer(); //< release memory set buffer to nullptr and size to zero 93 void shift_by_half(); 94 void clear_buffer(); 95 void flush_write(); 96 void fulfill_read(); 97 U_I available_in_cache(skippability direction) const; 98 }; 99 100 /// @} 101 102 } // end of namespace 103 104 #endif 105 106