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,...
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'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'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.