1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
|
// fgpickbest.cc
#include "fgpickbest.h"
#ifndef _FGALIST_H
#include "fgalist.h"
#endif
#ifndef _FGBDFNAME_H
#include "fgbdfname.h"
#endif
#ifndef _FGDLIST_H
#include "fgdlist.h"
#endif
#ifndef _FGMRANK_H
#include "fgmrank.h"
#endif
#ifndef _FGDLACTION_H
#include "fgdlaction.h"
#endif
#ifndef _FGDELACTION_H
#include "fgdelaction.h"
#endif
#ifndef __SGI_STL_MAP_H
#include <map.h>
#endif
#include <assert.h>
#undef DEBUG_PICKER
struct FGPickBest::Internal_FGPickBest {
Internal_FGPickBest(const FGString& fname);
int mRevisionsCount;
FGBrokenDownFileName mFileBits;
};
FGPickBest::Internal_FGPickBest::Internal_FGPickBest(const FGString& fname)
: mFileBits(fname)
{
}
FGPickBest::FGPickBest(FGConnectionInterface* pConnIf, const FGString& match,
int count)
: FGFilePickerInterface(pConnIf)
{
assert(count > 0);
mpInternals = new Internal_FGPickBest(match);
mpInternals->mRevisionsCount = count;
}
FGActionList
FGPickBest::DecideActions(const FGDirListing& localDir,
const FGDirListing& remoteDir)
{
FGActionList ret;
// Special structures used in this algorithm
typedef enum _floc {
kLocal = 0,
kRemote,
kBoth
} EFGFileLocation;
// n.b. 2nd arg, int, isn't allowed (by ANSI) to be of type
// EFGFileLocation
typedef pair<FGFileInfo, int> FGPickMapInfo;
typedef map<FGMatchRanking, FGPickMapInfo> FGPickMap;
typedef FGPickMap::iterator FGPickMapIterator;
typedef FGPickMap::const_iterator FGPickMapCIterator;
// The sacred map itself
FGPickMap mainMap;
// Inject all local matches into map
vector<FGFileInfo>::const_iterator iFiles;
for (iFiles = localDir.begin(); iFiles != localDir.end(); iFiles++) {
// Rule based matching only considers files
if (!iFiles->IsRegularFile()) {
continue;
}
FGString fileName = iFiles->GetFileName();
FGMatchRanking thisRank = mpInternals->mFileBits.GetRanking(fileName);
if (thisRank.IsMatch()) {
#ifdef DEBUG_PICKER
printf("Local file found\n");
#endif
FGPickMapInfo newPair;
newPair.first = *iFiles;
newPair.second = kLocal;
FGPickMap::value_type theValue(thisRank, newPair);
mainMap.insert(theValue);
}
}
// Now inject all remote files into the map
// Any duplicates get their location flag set to "both"
for (iFiles = remoteDir.begin(); iFiles != remoteDir.end(); iFiles++) {
FGString fileName = iFiles->GetFileName();
// Rule based matching only considers files
if (!iFiles->IsRegularFile()) {
continue;
}
FGMatchRanking thisRank = mpInternals->mFileBits.GetRanking(fileName);
// If we have less matches than we want, or the current match is
// better than our worst match yet, take it
if (thisRank.IsMatch()) {
#ifdef DEBUG_PICKER
printf("Remote file found\n");
#endif
// Two cases - rank value already in map, or not
FGPickMapIterator iMap = mainMap.find(thisRank);
if (iMap == mainMap.end()) {
// Not there yet
FGPickMapInfo newPair;
newPair.first = *iFiles;
newPair.second = kRemote;
FGPickMap::value_type theValue(thisRank, newPair);
mainMap.insert(theValue);
} else {
// Yes, already there
iMap->second.second = kBoth;
}
}
}
// Use our map to decide actions
// Empty map? Just get out..
if (mainMap.size() == 0) {
return ret;
}
FGPickMapCIterator iAllMap = mainMap.end();
// end() points off end => back iterator off one
iAllMap--;
int wanted = mpInternals->mRevisionsCount;
do {
// Case 1: we are in the wanted region
if (wanted > 0) {
// Within the wanted region, make download actions
// for all "remote only" files
if (iAllMap->second.second == kRemote) {
ret.push_back(new FGDownloadAction(iAllMap->second.first.GetFileName(),
mpConnIf,
localDir.GetDirName(),
iAllMap->second.first.GetSize()));
}
} else {
// Case 2: we are in the ditch region
// Within the ditch region, make delete actions for
// all "local only" or "local and remote" files
EFGFileLocation fl = (EFGFileLocation)iAllMap->second.second;
if (fl == kLocal || fl == kBoth) {
ret.push_back(new FGDeleteAction(iAllMap->second.first.GetFileName(),
localDir.GetDirName()));
}
}
// Make sure we only try and keep the top N matches on local disk
wanted--;
// Decrement the iterator (move towards worse matches)
} while (iAllMap-- != mainMap.begin());
return ret;
}
|