VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gvcache.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2017 Graeme Walker
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 //
18 // gvcache.cpp
19 //
20 
21 #include "gdef.h"
22 #include "gstr.h"
23 #include "gfile.h"
24 #include "groot.h"
25 #include "gprocess.h"
26 #include "gdatetime.h"
27 #include "gvcache.h"
28 #include "gassert.h"
29 #include "glog.h"
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h> // ::open()
33 #include <stdio.h> // ::rename()
34 #include <errno.h>
35 #include <unistd.h>
36 
37 Gv::Cache::Cache( const G::Path & base_dir , const std::string & name , size_t size ) :
38  m_base_dir(base_dir) ,
39  m_prefix(name.empty()?std::string():(name+".")) ,
40  m_cache_dir(base_dir+".cache") ,
41  m_list(size) ,
42  m_p(m_list.begin()) ,
43  m_ok(true)
44 {
45  G_ASSERT( name.find('/') == std::string::npos ) ;
46  G::Str::replaceAll( m_prefix , "/" , "" ) ;
47 
48  G_LOG( "Gv::Cache::ctor: cache dir=[" << m_cache_dir << "] size=" << m_list.size() ) ;
49  if( m_list.size() )
50  {
51  G::Root claim_root ;
52  G::File::mkdirs( m_cache_dir ) ;
53  }
54 
55  unsigned int i = 0U ;
56  for( List::iterator p = m_list.begin() ; p != m_list.end() ; ++p , i++ )
57  (*p).cache_path = G::Path(m_cache_dir+(m_prefix+G::Str::fromUInt(i))).str() ;
58 }
59 
61 {
62  G::Root claim_root ;
63  for( List::iterator p = m_list.begin() ; p != m_list.end() ; ++p )
64  {
65  if( (*p).fd != -1 )
66  ::close( (*p).fd ) ;
67  ::unlink( (*p).cache_path.c_str() ) ;
68  }
69 }
70 
71 std::string Gv::Cache::base() const
72 {
73  return m_base_dir.str() ;
74 }
75 
76 void Gv::Cache::fail( const char * where )
77 {
78  G_DEBUG( "Gv::Cache::fail: failed: " << where ) ;
79  G_WARNING_ONCE( "Gv::Cache::fail: one or more cache failures" ) ;
80  m_ok = false ;
81 }
82 
83 void Gv::Cache::store( const Gr::ImageBuffer & image_buffer , const std::string & commit_path ,
84  const std::string & commit_path_other , const std::string & same_as_path )
85 {
86  if( m_list.empty() ) return ;
87  if( ++m_p == m_list.end() )
88  m_p = m_list.begin() ;
89 
90  Entry & e = *m_p ;
91  e.commit_path = commit_path ;
92  e.commit_path_other = commit_path_other ;
93  e.same_as_path = same_as_path ;
94  open( e ) ;
95  write( e , image_buffer ) ;
96 }
97 
98 void Gv::Cache::open( Entry & e )
99 {
100  if( e.fd == -1 )
101  {
102  {
103  G::Root claim_root ;
104  e.fd = ::open( e.cache_path.c_str() , O_CREAT | O_TRUNC | O_WRONLY ,
105  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ) ;
106  }
107  if( e.fd == -1 )
108  fail( "open" ) ;
109  }
110 }
111 
112 void Gv::Cache::write( Entry & e , const Gr::ImageBuffer & image_buffer )
113 {
114  if( ::lseek( e.fd , 0L , SEEK_SET ) < 0 )
115  fail( "lseek" ) ;
116 
118  for( row_iterator part_p = Gr::imagebuffer::row_begin(image_buffer) ; part_p != Gr::imagebuffer::row_end(image_buffer) ; ++part_p )
119  {
120  const char * p = Gr::imagebuffer::row_ptr( part_p ) ;
121  size_t n = Gr::imagebuffer::row_size( part_p ) ;
122  if( n != 0U && ::write( e.fd , p , n ) != static_cast<ssize_t>(n) )
123  {
124  fail( "write" ) ;
125  break ;
126  }
127  }
128 }
129 
130 void Gv::Cache::commit( bool other )
131 {
132  size_t n = 0U ;
133  for( List::iterator p = m_list.begin() ; p != m_list.end() ; ++p )
134  {
135  if( (*p).fd >= 0 )
136  {
137  commit( *p , other ) ;
138  n++ ;
139  }
140  }
141  G_DEBUG( "Gv::Cache::commit: commited " << n << "/" << m_list.size() ) ;
142 }
143 
144 void Gv::Cache::commit( Entry & e , bool other )
145 {
146  close( e ) ;
147  const std::string & commit_path = other && !e.commit_path_other.empty() ? e.commit_path_other : e.commit_path ;
148  if( !e.same_as_path.empty() && move(e.same_as_path,commit_path) ) // avoid duplication
149  {
150  G::Root claim_root ;
151  G::File::remove( e.cache_path , G::File::NoThrow() ) ;
152  }
153  else
154  {
155  move( e.cache_path , commit_path ) ;
156  }
157 }
158 
159 void Gv::Cache::close( Entry & e )
160 {
161  int fd = e.fd ;
162  e.fd = -1 ;
163  if( ::close( fd ) < 0 )
164  fail( "close" ) ;
165 }
166 
167 bool Gv::Cache::move( const std::string & src , const std::string & dst )
168 {
169  int rc = -1 ;
170  {
171  G::Root claim_root ;
172  rc = ::rename( src.c_str() , dst.c_str() ) ;
173  }
174  if( rc < 0 )
175  {
176  int err = errno ;
177  if( err == ENOENT )
178  {
179  mkdirs( dst ) ;
180  G::Root claim_root ;
181  rc = ::rename( src.c_str() , dst.c_str() ) ;
182  }
183  }
184  if( rc < 0 )
185  fail( "rename" ) ;
186  else
187  G_DEBUG( "Gv::Cache::move: [" << src << "] -> [" << dst << "]" ) ;
188  return rc >= 0 ;
189 }
190 
191 void Gv::Cache::mkdirs( const G::Path & path )
192 {
193  bool ok = false ;
194  {
195  G::Path dir = path.dirname() ;
196  G::Root claim_root ;
197  ok = G::File::mkdirs( dir , G::File::NoThrow() ) ;
198  }
199  if( !ok )
200  fail( "mkdirs" ) ;
201 }
202 
203 /// \file gvcache.cpp
A traits class that can be specialised for Gr::ImageBuffer candidates.
Definition: grtraits.h:34
A class which acquires the process's special privileges on construction and releases them on destruct...
Definition: groot.h:49
Vectors ImageBuffer
An ImageBuffer is used to hold raw image data, typically in more than one chunk.
Definition: grimagebuffer.h:47
static bool mkdirs(const Path &dir, const NoThrow &, int=100)
Creates a directory and all necessary parents.
Definition: gfile.cpp:172
static std::string fromUInt(unsigned int ui)
Converts unsigned int 'ui' to a string.
Definition: gstr.cpp:315
static unsigned int replaceAll(std::string &s, const std::string &from, const std::string &to)
Does a global replace on string 's', replacing all occurances of sub-string 'from' with 'to'...
Definition: gstr.cpp:157
~Cache()
Destructor.
Definition: gvcache.cpp:60
Cache(const G::Path &base_dir, const std::string &name, size_t size)
Constructor. Paths are like "<base-dir>/.cache/<name>.123".
Definition: gvcache.cpp:37
void store(const Gr::ImageBuffer &, const std::string &commit_path, const std::string &commit_path_other=std::string(), const std::string &same_as=std::string())
Stores an image in the cache.
Definition: gvcache.cpp:83
Path dirname() const
Returns the path without the rightmost part, ignoring "." parts.
Definition: gpath.cpp:318
static bool remove(const Path &path, const NoThrow &)
Deletes the file or directory. Returns false on error.
Definition: gfile.cpp:29
void commit(bool other=false)
Commits all cached images to their non-cache location.
Definition: gvcache.cpp:130
An overload discriminator class for File methods.
Definition: gfile.h:53
std::string base() const
Returns the base directory, as passed to the constructor.
Definition: gvcache.cpp:71
A Path object represents a file system path.
Definition: gpath.h:72