32 using std::ostringstream;
35 BamCache *BamCache::_global_ptr =
nullptr;
49 PRC_DESC(
"The full path to a directory, local to this computer, in which "
50 "model and texture files will be cached on load. If a directory "
51 "name is specified here, files may be loaded from the cache "
52 "instead of from their actual pathnames, which may save load time, "
53 "especially if you are loading egg files instead of bam files, "
54 "or if you are loading models from a shared network drive. "
55 "If this is the empty string, no cache will be used."));
58 (
"model-cache-flush", 30,
59 PRC_DESC(
"This is the amount of time, in seconds, between automatic "
60 "flushes of the model-cache index."));
63 (
"model-cache-models",
true,
64 PRC_DESC(
"If this is set to true, models will be cached in the "
65 "model cache, as bam files."));
68 (
"model-cache-textures",
true,
69 PRC_DESC(
"If this is set to true, textures will also be cached in the "
70 "model cache, as txo files."));
73 (
"model-cache-compressed-textures",
false,
74 PRC_DESC(
"If this is set to true, compressed textures will be cached "
75 "in the model cache, in their compressed form as downloaded "
76 "by the GSG. This may be set in conjunction with "
77 "model-cache-textures, or it may be independent."));
80 (
"model-cache-compiled-shaders",
false,
81 PRC_DESC(
"If this is set to true, compiled shaders will be cached "
82 "in the model cache, in their binary form as downloaded "
86 (
"model-cache-max-kbytes", 10485760,
87 PRC_DESC(
"This is the maximum size of the model cache, in kilobytes."));
89 _cache_models = model_cache_models;
90 _cache_textures = model_cache_textures;
91 _cache_compressed_textures = model_cache_compressed_textures;
92 _cache_compiled_shaders = model_cache_compiled_shaders;
94 _flush_time = model_cache_flush;
95 _max_kbytes = model_cache_max_kbytes;
97 if (!model_cache_dir.empty()) {
98 set_root(model_cache_dir);
135 _index_stale_since = 0;
159 lookup(
const Filename &source_filename,
const string &cache_extension) {
165 Filename source_pathname(source_filename);
168 Filename rel_pathname(source_pathname);
179 return find_and_read_record(source_pathname, cache_filename);
191 nassertr(!record->_cache_pathname.empty(),
false);
192 nassertr(record->has_data(),
false);
202 Filename rel_pathname(record->_cache_pathname);
204 nassertr(rel_pathname.
is_local(),
false);
207 record->_recorded_time = time(
nullptr);
209 Filename cache_pathname = Filename::binary_filename(record->_cache_pathname);
215 string extension = current_thread->
get_unique_id() + string(
".tmp");
216 Filename temp_pathname = cache_pathname;
221 if (!dout.
open(temp_pathname)) {
223 <<
"Could not write cache file: " << temp_pathname <<
"\n";
225 emergency_read_only();
231 <<
"Unable to write to " << temp_pathname <<
"\n";
238 if (!writer.
init()) {
240 <<
"Unable to write Bam header to " << temp_pathname <<
"\n";
247 if (record->
get_data()->is_of_type(texture_type)) {
257 if (record->
get_data()->is_of_type(node_type)) {
263 <<
"Unable to write object to " << temp_pathname <<
"\n";
270 <<
"Unable to write object data to " << temp_pathname <<
"\n";
284 if (!vfs->
rename_file(temp_pathname, cache_pathname) && vfs->
exists(temp_pathname)) {
286 if (!vfs->
rename_file(temp_pathname, cache_pathname)) {
288 <<
"Unable to rename " << temp_pathname <<
" to "
289 << cache_pathname <<
"\n";
295 add_to_index(record);
306 emergency_read_only() {
308 "Could not write to the Bam Cache. Disabling future attempts.\n";
318 #if defined(HAVE_THREADS) || defined(DEBUG_THREADS)
326 if (_index_stale_since != 0) {
327 int elapsed = (int)time(
nullptr) - (int)_index_stale_since;
328 if (elapsed > _flush_time) {
333 #if defined(HAVE_THREADS) || defined(DEBUG_THREADS)
344 if (_index_stale_since == 0) {
356 if (!do_write_index(temp_pathname, _index)) {
357 emergency_read_only();
365 string old_index = _index_ref_contents;
374 _index_pathname = temp_pathname;
375 _index_ref_contents = new_index;
376 _index_stale_since = 0;
384 _index_ref_contents = orig_index;
395 _index->write(out, indent_level);
404 if (!read_index_pathname(_index_pathname, _index_ref_contents)) {
412 if (new_index !=
nullptr) {
413 merge_index(new_index);
419 Filename old_index_pathname = _index_pathname;
420 if (!read_index_pathname(_index_pathname, _index_ref_contents)) {
426 if (old_index_pathname == _index_pathname) {
442 read_index_pathname(
Filename &index_pathname,
string &index_ref_contents)
const {
444 index_ref_contents.clear();
450 string trimmed =
trim(index_ref_contents);
451 if (trimmed.empty()) {
468 if (_index_stale_since == 0) {
476 old_index->release_records();
477 new_index->release_records();
480 BamCacheIndex::Records::const_iterator ai = old_index->_records.begin();
481 BamCacheIndex::Records::const_iterator bi = new_index->_records.begin();
483 while (ai != old_index->_records.end() &&
484 bi != new_index->_records.end()) {
485 if ((*ai).first < (*bi).first) {
488 Filename cache_pathname(_root, record->get_cache_filename());
489 if (cache_pathname.exists()) {
491 _index->_records.insert(_index->_records.end(), BamCacheIndex::Records::value_type(record->get_source_pathname(), record));
495 }
else if ((*bi).first < (*ai).first) {
498 Filename cache_pathname(_root, record->get_cache_filename());
499 if (cache_pathname.exists()) {
501 _index->_records.insert(_index->_records.end(), BamCacheIndex::Records::value_type(record->get_source_pathname(), record));
509 if (*a_record == *b_record) {
512 _index->_records.insert(_index->_records.end(), BamCacheIndex::Records::value_type(a_record->get_source_pathname(), a_record));
518 Filename cache_pathname(_root, a_record->get_cache_filename());
520 if (cache_pathname.exists()) {
521 PT(
BamCacheRecord) record = do_read_record(cache_pathname,
false);
522 if (record !=
nullptr) {
523 _index->_records.insert(_index->_records.end(), BamCacheIndex::Records::value_type(record->get_source_pathname(), record));
533 while (ai != old_index->_records.end()) {
536 Filename cache_pathname(_root, record->get_cache_filename());
537 if (cache_pathname.exists()) {
539 _index->_records.insert(_index->_records.end(), BamCacheIndex::Records::value_type(record->get_source_pathname(), record));
544 while (bi != new_index->_records.end()) {
547 Filename cache_pathname(_root, record->get_cache_filename());
548 if (cache_pathname.exists()) {
550 _index->_records.insert(_index->_records.end(), BamCacheIndex::Records::value_type(record->get_source_pathname(), record));
555 _index->process_new_records();
566 if (contents ==
nullptr) {
568 <<
"Unable to read directory " << _root <<
", caching disabled.\n";
576 int num_files = contents->get_num_files();
577 for (
int ci = 0; ci < num_files; ++ci) {
579 Filename filename = file->get_filename();
585 if (record ==
nullptr) {
587 if (util_cat.is_debug()) {
589 <<
"Deleting invalid " << pathname <<
"\n";
594 record->_record_access_time = record->_recorded_time;
596 bool inserted = _index->_records.insert(BamCacheIndex::Records::value_type(record->get_source_pathname(), record)).second;
599 <<
"Multiple cache files defining " << record->get_source_pathname() <<
"\n";
605 _index->process_new_records();
607 _index_stale_since = time(
nullptr);
620 if (_index->add_record(new_record)) {
630 remove_from_index(
const Filename &source_pathname) {
631 if (_index->remove_record(source_pathname)) {
642 if (_index->_cache_size == 0) {
647 if (_index->_cache_size / 1024 > _max_kbytes) {
648 while (_index->_cache_size / 1024 > _max_kbytes) {
650 if (record ==
nullptr) {
655 Filename cache_pathname(_root, record->get_cache_filename());
656 if (util_cat.is_debug()) {
658 <<
"Deleting " << cache_pathname
659 <<
" to keep cache size below " << _max_kbytes <<
"K\n";
672 do_read_index(
const Filename &index_pathname) {
673 if (index_pathname.empty()) {
678 if (!din.
open(index_pathname)) {
680 <<
"Could not read index file: " << index_pathname <<
"\n";
687 << index_pathname <<
" is not an index file.\n";
691 if (head != _bam_header) {
693 << index_pathname <<
" is not an index file.\n";
698 if (!reader.init()) {
704 if (
object ==
nullptr) {
706 <<
"Cache index " << index_pathname <<
" is empty.\n";
709 }
else if (!object->
is_of_type(BamCacheIndex::get_class_type())) {
711 <<
"Cache index " << index_pathname <<
" contains a "
712 <<
object->
get_type() <<
", not a BamCacheIndex.\n";
717 if (!reader.resolve()) {
719 <<
"Unable to fully resolve cache index file.\n";
733 if (!dout.
open(index_pathname)) {
735 <<
"Could not write index file: " << index_pathname <<
"\n";
742 <<
"Unable to write to " << index_pathname <<
"\n";
749 if (!writer.init()) {
754 if (!writer.write_object(index)) {
769 find_and_read_record(
const Filename &source_pathname,
774 read_record(source_pathname, cache_filename, pass);
775 if (record !=
nullptr) {
776 add_to_index(record);
788 read_record(
const Filename &source_pathname,
792 Filename cache_pathname(_root, cache_filename);
795 strm << cache_pathname.get_basename_wo_extension() <<
"_" << pass;
796 cache_pathname.set_basename_wo_extension(strm.str());
799 if (!cache_pathname.exists()) {
801 if (util_cat.is_debug()) {
803 <<
"Declaring new cache file " << cache_pathname <<
" for " << source_pathname <<
"\n";
807 record->_cache_pathname = cache_pathname;
811 if (util_cat.is_debug()) {
813 <<
"Reading cache file " << cache_pathname <<
" for " << source_pathname <<
"\n";
817 if (record ==
nullptr) {
819 if (util_cat.is_debug()) {
821 <<
"Deleting invalid cache file " << cache_pathname <<
"\n";
824 remove_from_index(source_pathname);
828 record->_cache_pathname = cache_pathname;
832 if (record->get_source_pathname() != source_pathname) {
834 if (util_cat.is_debug()) {
836 <<
"Cache file " << cache_pathname <<
" references "
837 << record->get_source_pathname() <<
", not "
838 << source_pathname <<
"\n";
843 if (!record->has_data()) {
848 record->_cache_pathname = cache_pathname;
856 do_read_record(
const Filename &cache_pathname,
bool read_data) {
858 if (!din.
open(cache_pathname)) {
859 if (util_cat.is_debug()) {
861 <<
"Could not read cache file: " << cache_pathname <<
"\n";
868 if (util_cat.is_debug()) {
870 << cache_pathname <<
" is not a cache file.\n";
875 if (head != _bam_header) {
876 if (util_cat.is_debug()) {
878 << cache_pathname <<
" is not a cache file.\n";
884 if (!reader.init()) {
889 if (
object ==
nullptr) {
890 if (util_cat.is_debug()) {
892 << cache_pathname <<
" is empty.\n";
896 }
else if (!object->
is_of_type(BamCacheRecord::get_class_type())) {
897 if (util_cat.is_debug()) {
899 <<
"Cache file " << cache_pathname <<
" contains a "
900 <<
object->
get_type() <<
", not a BamCacheRecord.\n";
906 if (!reader.resolve()) {
907 if (util_cat.is_debug()) {
909 <<
"Unable to fully resolve cache record in " << cache_pathname <<
"\n";
924 if (reader.read_object(ptr, ref_ptr)) {
925 if (!reader.resolve()) {
926 if (util_cat.is_debug()) {
928 <<
"Unable to fully resolve cached object in " << cache_pathname <<
"\n";
942 record->_record_size = vfile->get_file_size(&in);
945 record->_record_access_time = time(
nullptr);
955 hash_filename(
const string &filename) {
959 hv.hash_string(filename);
964 #else // HAVE_OPENSSL
966 unsigned int hash = 0;
967 for (string::const_iterator si = filename.begin();
968 si != filename.end();
970 hash = (hash * 9109) + (
unsigned int)(*si);
974 strm << std::hex << std::setw(8) << std::setfill(
'0') << hash;
977 #endif // HAVE_OPENSSL
987 if (_global_ptr->_root.empty()) {