Panda3D
|
00001 // Filename: bamCacheIndex.cxx 00002 // Created by: drose (19Jun06) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "bamCacheIndex.h" 00016 #include "indent.h" 00017 #include <algorithm> 00018 00019 TypeHandle BamCacheIndex::_type_handle; 00020 00021 00022 //////////////////////////////////////////////////////////////////// 00023 // Function: BamCacheIndex::Destructor 00024 // Access: Published 00025 // Description: 00026 //////////////////////////////////////////////////////////////////// 00027 BamCacheIndex:: 00028 ~BamCacheIndex() { 00029 #ifndef NDEBUG 00030 // We need to "empty" the linked list to make the LinkedListNode 00031 // destructors happy. 00032 release_records(); 00033 #endif 00034 } 00035 00036 //////////////////////////////////////////////////////////////////// 00037 // Function: BamCacheIndex::write 00038 // Access: Public 00039 // Description: 00040 //////////////////////////////////////////////////////////////////// 00041 void BamCacheIndex:: 00042 write(ostream &out, int indent_level) const { 00043 indent(out, indent_level) 00044 << "BamCacheIndex, " << _records.size() << " records:\n"; 00045 00046 Records::const_iterator ri; 00047 for (ri = _records.begin(); ri != _records.end(); ++ri) { 00048 BamCacheRecord *record = (*ri).second; 00049 indent(out, indent_level + 2) 00050 << setw(10) << record->_record_size << " " 00051 << record->get_cache_filename() << " " 00052 << record->get_source_pathname() << "\n"; 00053 } 00054 out << "\n"; 00055 indent(out, indent_level) 00056 << setw(12) << _cache_size << " bytes total\n"; 00057 } 00058 00059 //////////////////////////////////////////////////////////////////// 00060 // Function: BamCacheIndex::process_new_records 00061 // Access: Private 00062 // Description: Should be called after the _records index has been 00063 // filled externally, this will sort the records by 00064 // access time and calculate _cache_size. 00065 //////////////////////////////////////////////////////////////////// 00066 void BamCacheIndex:: 00067 process_new_records() { 00068 nassertv(_cache_size == 0); 00069 00070 // Fill up a vector so we can sort the records into order by access 00071 // time. 00072 RecordVector rv; 00073 rv.reserve(_records.size()); 00074 00075 Records::const_iterator ri; 00076 for (ri = _records.begin(); ri != _records.end(); ++ri) { 00077 BamCacheRecord *record = (*ri).second; 00078 _cache_size += record->_record_size; 00079 rv.push_back(record); 00080 } 00081 00082 sort(rv.begin(), rv.end(), BamCacheRecord::SortByAccessTime()); 00083 00084 // Now put them into the linked list. 00085 RecordVector::const_iterator rvi; 00086 for (rvi = rv.begin(); rvi != rv.end(); ++rvi) { 00087 BamCacheRecord *record = *rvi; 00088 record->insert_before(this); 00089 } 00090 } 00091 00092 //////////////////////////////////////////////////////////////////// 00093 // Function: BamCacheIndex::release_records 00094 // Access: Private 00095 // Description: This is the inverse of process_new_records: it 00096 // releases the records from the linked list, so that 00097 // they may be added to another index or whatever. 00098 // Calling this, of course, invalidates the index until 00099 // process_new_records() is called again. 00100 //////////////////////////////////////////////////////////////////// 00101 void BamCacheIndex:: 00102 release_records() { 00103 Records::const_iterator ri; 00104 for (ri = _records.begin(); ri != _records.end(); ++ri) { 00105 BamCacheRecord *record = (*ri).second; 00106 record->_next = NULL; 00107 record->_prev = NULL; 00108 } 00109 _next = this; 00110 _prev = this; 00111 _cache_size = 0; 00112 } 00113 00114 //////////////////////////////////////////////////////////////////// 00115 // Function: BamCacheIndex::evict_old_file 00116 // Access: Private 00117 // Description: Evicts an old file from the cache. Records the 00118 // record. Returns NULL if the cache is empty. 00119 //////////////////////////////////////////////////////////////////// 00120 PT(BamCacheRecord) BamCacheIndex:: 00121 evict_old_file() { 00122 if (_next == this) { 00123 // Nothing in the cache. 00124 return NULL; 00125 } 00126 00127 // The first record in the linked list is the least-recently-used 00128 // one. 00129 PT(BamCacheRecord) record = (BamCacheRecord *)_next; 00130 bool removed = remove_record(record->get_source_pathname()); 00131 nassertr(removed, NULL); 00132 00133 return record; 00134 } 00135 00136 //////////////////////////////////////////////////////////////////// 00137 // Function: BamCacheIndex::add_record 00138 // Access: Private 00139 // Description: Adds a newly-created BamCacheRecord into the index. 00140 // If a matching record is already in the index, it is 00141 // replaced with the new record. Returns true if the 00142 // record was added, or false if the equivalent record 00143 // was already there and the index is unchanged. 00144 //////////////////////////////////////////////////////////////////// 00145 bool BamCacheIndex:: 00146 add_record(BamCacheRecord *record) { 00147 pair<Records::iterator, bool> result = 00148 _records.insert(Records::value_type(record->get_source_pathname(), record)); 00149 if (!result.second) { 00150 // We already had a record for this filename; it gets replaced. 00151 BamCacheRecord *orig_record = (*result.first).second; 00152 orig_record->remove_from_list(); 00153 if (*orig_record == *record) { 00154 // Well, never mind. The record hasn't changed. 00155 orig_record->insert_before(this); 00156 return false; 00157 } 00158 00159 _cache_size -= orig_record->_record_size; 00160 (*result.first).second = record; 00161 } 00162 record->insert_before(this); 00163 00164 _cache_size += record->_record_size; 00165 return true; 00166 } 00167 00168 //////////////////////////////////////////////////////////////////// 00169 // Function: BamCacheIndex::remove_record 00170 // Access: Private 00171 // Description: Searches for the matching record in the index and 00172 // removes it if it is found. Returns true if the 00173 // record was found and removed, or false if there was 00174 // no such record and the index is unchanged. 00175 //////////////////////////////////////////////////////////////////// 00176 bool BamCacheIndex:: 00177 remove_record(const Filename &source_pathname) { 00178 Records::iterator ri = _records.find(source_pathname); 00179 if (ri == _records.end()) { 00180 // No entry for this record; no problem. 00181 return false; 00182 } 00183 00184 BamCacheRecord *record = (*ri).second; 00185 record->remove_from_list(); 00186 _cache_size -= record->_record_size; 00187 _records.erase(ri); 00188 return true; 00189 } 00190 00191 //////////////////////////////////////////////////////////////////// 00192 // Function: BamCacheIndex::register_with_read_factory 00193 // Access: Public, Static 00194 // Description: Tells the BamReader how to create objects of type 00195 // BamCacheRecord. 00196 //////////////////////////////////////////////////////////////////// 00197 void BamCacheIndex:: 00198 register_with_read_factory() { 00199 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); 00200 } 00201 00202 //////////////////////////////////////////////////////////////////// 00203 // Function: BamCacheIndex::write_datagram 00204 // Access: Public, Virtual 00205 // Description: Writes the contents of this object to the datagram 00206 // for shipping out to a Bam file. 00207 //////////////////////////////////////////////////////////////////// 00208 void BamCacheIndex:: 00209 write_datagram(BamWriter *manager, Datagram &dg) { 00210 TypedWritable::write_datagram(manager, dg); 00211 00212 dg.add_uint32(_records.size()); 00213 Records::const_iterator ri; 00214 for (ri = _records.begin(); ri != _records.end(); ++ri) { 00215 manager->write_pointer(dg, (*ri).second); 00216 } 00217 } 00218 00219 //////////////////////////////////////////////////////////////////// 00220 // Function: BamCacheIndex::make_from_bam 00221 // Access: Protected, Static 00222 // Description: This function is called by the BamReader's factory 00223 // when a new object of type BamCacheIndex is encountered 00224 // in the Bam file. It should create the BamCacheIndex 00225 // and extract its information from the file. 00226 //////////////////////////////////////////////////////////////////// 00227 TypedWritable *BamCacheIndex:: 00228 make_from_bam(const FactoryParams ¶ms) { 00229 BamCacheIndex *object = new BamCacheIndex; 00230 DatagramIterator scan; 00231 BamReader *manager; 00232 00233 parse_params(params, scan, manager); 00234 object->fillin(scan, manager); 00235 00236 return object; 00237 } 00238 00239 //////////////////////////////////////////////////////////////////// 00240 // Function: BamCacheIndex::complete_pointers 00241 // Access: Public, Virtual 00242 // Description: Receives an array of pointers, one for each time 00243 // manager->read_pointer() was called in fillin(). 00244 // Returns the number of pointers processed. 00245 //////////////////////////////////////////////////////////////////// 00246 int BamCacheIndex:: 00247 complete_pointers(TypedWritable **p_list, BamReader *manager) { 00248 int pi = TypedWritable::complete_pointers(p_list, manager); 00249 00250 RecordVector::iterator vi; 00251 for (vi = _record_vector.begin(); vi != _record_vector.end(); ++vi) { 00252 PT(BamCacheRecord) record = DCAST(BamCacheRecord, p_list[pi++]); 00253 (*vi) = record; 00254 00255 bool inserted = _records.insert(Records::value_type(record->get_source_pathname(), record)).second; 00256 if (!inserted) { 00257 util_cat.info() 00258 << "Multiple cache files defining " << record->get_source_pathname() 00259 << " in index.\n"; 00260 } 00261 } 00262 00263 _record_vector.clear(); 00264 00265 process_new_records(); 00266 00267 return pi; 00268 } 00269 00270 //////////////////////////////////////////////////////////////////// 00271 // Function: BamCacheIndex::fillin 00272 // Access: Protected 00273 // Description: This internal function is called by make_from_bam to 00274 // read in all of the relevant data from the BamFile for 00275 // the new BamCacheIndex. 00276 //////////////////////////////////////////////////////////////////// 00277 void BamCacheIndex:: 00278 fillin(DatagramIterator &scan, BamReader *manager) { 00279 TypedWritable::fillin(scan, manager); 00280 00281 int num_records = scan.get_uint32(); 00282 _record_vector.reserve(num_records); 00283 for (int i = 0; i < num_records; ++i) { 00284 _record_vector.push_back(NULL); 00285 manager->read_pointer(scan); 00286 } 00287 }