Panda3D
bamCacheRecord.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file bamCacheRecord.cxx
10  * @author drose
11  * @date 2006-06-09
12  */
13 
14 #include "bamCacheRecord.h"
15 #include "bamReader.h"
16 #include "bamWriter.h"
17 #include "virtualFileSystem.h"
18 #include "virtualFile.h"
19 #include "indent.h"
20 #include "config_putil.h" // util_cat
21 
22 TypeHandle BamCacheRecord::_type_handle;
23 
24 /**
25  * Used when reading from a bam file.
26  */
27 BamCacheRecord::
28 BamCacheRecord() :
29  _recorded_time(0),
30  _record_size(0),
31  _source_timestamp(0),
32  _ptr(nullptr),
33  _ref_ptr(nullptr),
34  _record_access_time(0)
35 {
36 }
37 
38 /**
39  * Use BamCache::lookup() to create one of these.
40  */
41 BamCacheRecord::
42 BamCacheRecord(const Filename &source_pathname,
43  const Filename &cache_filename) :
44  _source_pathname(source_pathname),
45  _cache_filename(cache_filename),
46  _recorded_time(0),
47  _record_size(0),
48  _source_timestamp(0),
49  _ptr(nullptr),
50  _ref_ptr(nullptr),
51  _record_access_time(0)
52 {
53 }
54 
55 /**
56  * Use make_copy() to make a copy. The copy does not share the data pointer.
57  */
58 BamCacheRecord::
59 BamCacheRecord(const BamCacheRecord &copy) :
60  _source_pathname(copy._source_pathname),
61  _cache_filename(copy._cache_filename),
62  _recorded_time(copy._recorded_time),
63  _record_size(copy._record_size),
64  _source_timestamp(copy._source_timestamp),
65  _ptr(nullptr),
66  _ref_ptr(nullptr),
67  _record_access_time(copy._record_access_time)
68 {
69 }
70 
71 /**
72  *
73  */
74 BamCacheRecord::
75 ~BamCacheRecord() {
76  clear_data();
77 }
78 
79 /**
80  * Returns true if all of the dependent files are still the same as when the
81  * cache was recorded, false otherwise.
82  */
86 
87  if (util_cat.is_debug()) {
88  util_cat.debug()
89  << "Validating dependents for " << get_source_pathname() << "\n";
90  }
91 
92  DependentFiles::const_iterator fi;
93  for (fi = _files.begin(); fi != _files.end(); ++fi) {
94  const DependentFile &dfile = (*fi);
95  PT(VirtualFile) file = vfs->get_file(dfile._pathname);
96  if (file == nullptr) {
97  // No such file.
98  if (dfile._timestamp != 0) {
99  if (util_cat.is_debug()) {
100  util_cat.debug()
101  << dfile._pathname << " does not exist.\n";
102  }
103  return false;
104  }
105  } else {
106  if (file->get_timestamp() != dfile._timestamp ||
107  file->get_file_size() != dfile._size) {
108  // File has changed timestamp or size.
109  if (util_cat.is_debug()) {
110  util_cat.debug()
111  << dfile._pathname << " has changed timestamp or size.\n";
112  }
113  return false;
114  }
115  }
116 
117  // Presumably, the file is unchanged.
118  if (util_cat.is_debug()) {
119  util_cat.debug()
120  << dfile._pathname << " is unchanged.\n";
121  }
122  }
123 
124  if (util_cat.is_debug()) {
125  util_cat.debug()
126  << "Dependents valid.\n";
127  }
128 
129  return true;
130 }
131 
132 
133 /**
134  * Empties the list of files that contribute to the data in this record.
135  */
136 void BamCacheRecord::
138  _files.clear();
139 }
140 
141 /**
142  * Adds the indicated file to the list of files that will be loaded to
143  * generate the data in this record. This should be called once for the
144  * primary source file, and again for each secondary source file, if any.
145  */
146 void BamCacheRecord::
147 add_dependent_file(const Filename &pathname) {
149 
150  _files.push_back(DependentFile());
151  DependentFile &dfile = _files.back();
152  dfile._pathname = pathname;
153  dfile._pathname.make_absolute();
154 
155  PT(VirtualFile) file = vfs->get_file(dfile._pathname);
156  if (file == nullptr) {
157  // No such file.
158  dfile._timestamp = 0;
159  dfile._size = 0;
160 
161  } else {
162  dfile._timestamp = file->get_timestamp();
163  dfile._size = file->get_file_size();
164 
165  if (dfile._pathname == _source_pathname) {
166  _source_timestamp = dfile._timestamp;
167  }
168  }
169 }
170 
171 /**
172  * Variant of add_dependent_file that takes an already opened VirtualFile.
173  */
174 void BamCacheRecord::
176  _files.push_back(DependentFile());
177  DependentFile &dfile = _files.back();
178  dfile._pathname = file->get_filename();
179  dfile._pathname.make_absolute();
180 
181  dfile._timestamp = file->get_timestamp();
182  dfile._size = file->get_file_size();
183 
184  if (dfile._pathname == _source_pathname) {
185  _source_timestamp = dfile._timestamp;
186  }
187 }
188 
189 /**
190  *
191  */
192 void BamCacheRecord::
193 output(std::ostream &out) const {
194  out << "BamCacheRecord " << get_source_pathname();
195 }
196 
197 /**
198  *
199  */
200 void BamCacheRecord::
201 write(std::ostream &out, int indent_level) const {
202  indent(out, indent_level)
203  << "BamCacheRecord " << get_source_pathname() << "\n";
204  indent(out, indent_level)
205  << "source " << format_timestamp(_source_timestamp) << "\n";
206  indent(out, indent_level)
207  << "recorded " << format_timestamp(_recorded_time) << "\n";
208 
209  indent(out, indent_level)
210  << _files.size() << " dependent files.\n";
211  DependentFiles::const_iterator fi;
212  for (fi = _files.begin(); fi != _files.end(); ++fi) {
213  const DependentFile &dfile = (*fi);
214  indent(out, indent_level + 2)
215  << std::setw(10) << dfile._size << " "
216  << format_timestamp(dfile._timestamp) << " "
217  << dfile._pathname << "\n";
218  }
219 }
220 
221 /**
222  * Returns a timestamp value formatted nicely for output.
223  */
224 std::string BamCacheRecord::
225 format_timestamp(time_t timestamp) {
226  static const size_t buffer_size = 512;
227  char buffer[buffer_size];
228 
229  if (timestamp == 0) {
230  // A zero timestamp is a special case.
231  return " (no date) ";
232  }
233 
234  time_t now = time(nullptr);
235  struct tm atm;
236 #ifdef _WIN32
237  localtime_s(&atm, &timestamp);
238 #else
239  localtime_r(&timestamp, &atm);
240 #endif
241 
242  if (timestamp > now || (now - timestamp > 86400 * 365)) {
243  // A timestamp in the future, or more than a year in the past, gets a year
244  // appended.
245  strftime(buffer, buffer_size, "%b %d %Y", &atm);
246  } else {
247  // Otherwise, within the past year, show the date and time.
248  strftime(buffer, buffer_size, "%b %d %H:%M", &atm);
249  }
250 
251  return buffer;
252 }
253 
254 /**
255  * Tells the BamReader how to create objects of type BamCacheRecord.
256  */
257 void BamCacheRecord::
259  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
260 }
261 
262 /**
263  * Writes the contents of this object to the datagram for shipping out to a
264  * Bam file.
265  */
266 void BamCacheRecord::
269  dg.add_string(_source_pathname);
270  dg.add_string(_cache_filename);
271  dg.add_uint32(_recorded_time);
272  dg.add_uint64(_record_size);
273 
274  dg.add_uint16(_files.size());
275  DependentFiles::const_iterator fi;
276  for (fi = _files.begin(); fi != _files.end(); ++fi) {
277  const DependentFile &file = (*fi);
278  dg.add_string(file._pathname);
279  dg.add_uint32(file._timestamp);
280  dg.add_uint64(file._size);
281  }
282 }
283 
284 /**
285  * This function is called by the BamReader's factory when a new object of
286  * type BamCacheRecord is encountered in the Bam file. It should create the
287  * BamCacheRecord and extract its information from the file.
288  */
289 TypedWritable *BamCacheRecord::
290 make_from_bam(const FactoryParams &params) {
291  BamCacheRecord *object = new BamCacheRecord;
292  DatagramIterator scan;
293  BamReader *manager;
294 
295  parse_params(params, scan, manager);
296  object->fillin(scan, manager);
297 
298  return object;
299 }
300 
301 /**
302  * This internal function is called by make_from_bam to read in all of the
303  * relevant data from the BamFile for the new BamCacheRecord.
304  */
305 void BamCacheRecord::
306 fillin(DatagramIterator &scan, BamReader *manager) {
308 
309  _source_pathname = scan.get_string();
310  _cache_filename = scan.get_string();
311  _recorded_time = scan.get_uint32();
312  _record_size = scan.get_uint64();
313 
314  unsigned int num_files = scan.get_uint16();
315  _files.reserve(num_files);
316  for (unsigned int i = 0; i < num_files; ++i) {
317  _files.push_back(DependentFile());
318  DependentFile &file = _files.back();
319  file._pathname = scan.get_string();
320  file._timestamp = scan.get_uint32();
321  file._size = scan.get_uint64();
322 
323  // If we come across the original source file (we normally expect to),
324  // record that as its timestamp.
325  if (file._pathname == _source_pathname) {
326  _source_timestamp = file._timestamp;
327  }
328  }
329 }
uint64_t get_uint64()
Extracts an unsigned 64-bit integer.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
A hierarchy of directories and files that appears to be one continuous file system, even though the files may originate from several different sources that may not be related to the actual OS&#39;s file system.
virtual std::streamsize get_file_size(std::istream *stream) const
Returns the current size on disk (or wherever it is) of the already-open file.
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
virtual time_t get_timestamp() const
Returns a time_t value that represents the time the file was last modified, to within whatever precis...
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
The abstract base class for a file or directory within the VirtualFileSystem.
Definition: virtualFile.h:35
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::string get_string()
Extracts a variable-length string.
virtual void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is intended to be called by each class&#39;s make_from_bam() method to read in all...
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
void add_uint32(uint32_t value)
Adds an unsigned 32-bit integer to the datagram.
Definition: datagram.I:94
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
void parse_params(const FactoryParams &params, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable&#39;s make function...
Definition: bamReader.I:275
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
An instance of this class is written to the front of a Bam or Txo file to make the file a cached inst...
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
void add_string(const std::string &str)
Adds a variable-length string to the datagram.
Definition: datagram.I:219
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
uint32_t get_uint32()
Extracts an unsigned 32-bit integer.
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:73
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
static void register_with_read_factory()
Tells the BamReader how to create objects of type BamCacheRecord.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void make_absolute()
Converts the filename to a fully-qualified pathname from the root (if it is a relative pathname)...
Definition: filename.cxx:968
void clear_dependent_files()
Empties the list of files that contribute to the data in this record.
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void add_dependent_file(const Filename &pathname)
Adds the indicated file to the list of files that will be loaded to generate the data in this record...
A class to retrieve the individual data elements previously stored in a Datagram. ...
bool dependents_unchanged() const
Returns true if all of the dependent files are still the same as when the cache was recorded...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
void add_uint64(uint64_t value)
Adds an unsigned 64-bit integer to the datagram.
Definition: datagram.I:103
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.