Panda3D

bamCacheIndex.cxx

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 &params) {
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 }
 All Classes Functions Variables Enumerations