cache.cpp

Go to the documentation of this file.
00001 /*
00002         Description: file names persistent cache
00003 
00004         Author: Marco Costalba (C) 2005-2006
00005 
00006         Copyright: See COPYING file that comes with this distribution
00007 
00008 */
00009 #include <qfile.h>
00010 #include <qdir.h>
00011 #include <qapplication.h>
00012 #include <qdatastream.h>
00013 #include "cache.h"
00014 
00015 using namespace QGit;
00016 
00017 bool Cache::save(const QString& gitDir, const RevFileMap& rf,
00018                  const StrVect& dirs, const StrVect& files) {
00019 
00020         if (gitDir.isEmpty() || rf.isEmpty())
00021                 return false;
00022 
00023         QString path(gitDir + C_DAT_FILE);
00024         QString tmpPath(path + BAK_EXT);
00025 
00026         QDir dir;
00027         if (!dir.exists(gitDir)) {
00028                 dbs("Git directory not found, unable to save cache");
00029                 return false;
00030         }
00031         QFile f(tmpPath);
00032         if (!f.open(IO_WriteOnly))
00033                 return false;
00034 
00035         dbs("Saving cache. Please wait...");
00036 
00037         // compress in memory before write to file
00038         QByteArray data;
00039         QDataStream stream(data, IO_WriteOnly);
00040 
00041         // Write a header with a "magic number" and a version
00042         stream << (Q_UINT32)C_MAGIC;
00043         stream << (Q_INT32)C_VERSION;
00044 
00045         stream << (Q_INT32)dirs.count();
00046         for (uint i = 0; i < dirs.count(); ++i)
00047                 stream << dirs[i];
00048 
00049         stream << (Q_INT32)files.count();
00050         for (uint i = 0; i < files.count(); ++i)
00051                 stream << files[i];
00052 
00053         // to achieve a better compression we save the sha's as
00054         // one very long string instead of feeding the stream with
00055         // each one. With this trick we gain a 15% size reduction
00056         // in the final compressed file. The save/load speed is
00057         // almost the same.
00058         uint bufSize = rf.count() * 40 + 1000; // a little bit more space then required
00059         stream << (Q_INT32)bufSize;
00060 
00061         QString buf;
00062         buf.reserve(bufSize);
00063         QDictIterator<RevFile> it(rf);
00064         for ( ; it.current(); ++it) {
00065 
00066                 SCRef sha = it.currentKey();
00067                 if (   sha == ZERO_SHA
00068                     || sha == CUSTOM_SHA
00069                     || sha.startsWith("A")) // ALL_MERGE_FILES + rev sha
00070                         continue;
00071 
00072                 buf.append(sha);
00073         }
00074         stream << buf;
00075 
00076         for (it.toFirst(); it.current(); ++it) {
00077 
00078                 SCRef sha = it.currentKey();
00079                 if (   sha == ZERO_SHA
00080                     || sha == CUSTOM_SHA
00081                     || sha.startsWith("A")) // ALL_MERGE_FILES + rev sha
00082                         continue;
00083 
00084                 const RevFile* rf = *it;
00085                 stream << rf->names;
00086                 stream << rf->dirs;
00087 
00088                 // skip common case of only modified files
00089                 bool isEmpty = rf->onlyModified;
00090                 stream << (Q_UINT32)isEmpty;
00091                 if (!isEmpty)
00092                         stream << rf->status;
00093 
00094                 // skip common case of just one parent
00095                 isEmpty = (rf->mergeParent.isEmpty() || rf->mergeParent.last() == 1);
00096                 stream << (Q_UINT32)isEmpty;
00097                 if (!isEmpty)
00098                         stream << rf->mergeParent;
00099 
00100                 // skip common case of no rename/copies
00101                 isEmpty = rf->extStatus.isEmpty();
00102                 stream << (Q_UINT32)isEmpty;
00103                 if (!isEmpty)
00104                         stream << rf->extStatus;
00105         }
00106         dbs("Compressing data...");
00107         f.writeBlock(qCompress(data)); // no need to encode with compressed data
00108         f.close();
00109 
00110         // rename C_DAT_FILE + BAK_EXT -> C_DAT_FILE
00111         if (dir.exists(path)) {
00112                 if (!dir.remove(path)) {
00113                         dbs("access denied to " + path);
00114                         dir.remove(tmpPath);
00115                         return false;
00116                 }
00117         }
00118         dir.rename(tmpPath, path);
00119         dbs("Done.");
00120         return true;
00121 }
00122 
00123 bool Cache::load(const QString& gitDir, RevFileMap& rfm, StrVect& dirs, StrVect& files) {
00124 
00125         // check for cache file
00126         QString path(gitDir + C_DAT_FILE);
00127         QFile f(path);
00128         if (!f.exists())
00129                 return true; // no cache file is not an error
00130 
00131         if (!f.open(IO_ReadOnly))
00132                 return false;
00133 
00134         QDataStream* stream = new QDataStream(qUncompress(f.readAll()), IO_ReadOnly);
00135         Q_UINT32 magic;
00136         Q_INT32 version;
00137         Q_INT32 dirsNum, filesNum, bufSize;
00138         *stream >> magic;
00139         *stream >> version;
00140         if (magic != C_MAGIC || version != C_VERSION) {
00141                 f.close();
00142                 delete stream;
00143                 return false;
00144         }
00145         // read the data
00146         *stream >> dirsNum;
00147         dirs.resize(dirsNum);
00148         for (int i = 0; i < dirsNum; ++i)
00149                 *stream >> dirs[i];
00150 
00151         *stream >> filesNum;
00152         files.resize(filesNum);
00153         for (int i = 0; i < filesNum; ++i)
00154                 *stream >> files[i];
00155 
00156         *stream >> bufSize;
00157         QString buf;
00158         buf.reserve(bufSize);
00159         *stream >> buf;
00160 
00161         uint bufIdx = 0;
00162         bool isEmpty;
00163         Q_UINT32 tmp;
00164         while (!stream->atEnd()) {
00165 
00166                 RevFile* rf = new RevFile();
00167                 *stream >> rf->names;
00168                 *stream >> rf->dirs;
00169 
00170                 *stream >> tmp;
00171                 rf->onlyModified = (bool)tmp;
00172                 if (!rf->onlyModified)
00173                         *stream >> rf->status;
00174 
00175                 *stream >> tmp;
00176                 isEmpty = (bool)tmp;
00177                 if (!isEmpty)
00178                         *stream >> rf->mergeParent;
00179 
00180                 *stream >> tmp;
00181                 isEmpty = (bool)tmp;
00182                 if (!isEmpty)
00183                         *stream >> rf->extStatus;
00184 
00185                 SCRef sha(buf.mid(bufIdx, 40));
00186                 rfm.insert(sha, rf);
00187                 bufIdx += 40;
00188         }
00189         f.close();
00190         delete stream;
00191         return true;
00192 }

Generated on Fri Dec 7 21:57:36 2007 for QGit by  doxygen 1.5.3