|
@@ -2365,6 +2365,34 @@ inline void dfCheckRoot(const char *trc,Owned<IPropertyTree> &root,IRemoteConnec
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+class CFileChangeWriteLock
|
|
|
+{
|
|
|
+ Owned<IRemoteConnection> &conn;
|
|
|
+ Owned<IPropertyTree> &root;
|
|
|
+ unsigned timeoutMs, prevMode;
|
|
|
+public:
|
|
|
+ CFileChangeWriteLock(Owned<IRemoteConnection> &_conn, unsigned _timeoutMs, Owned<IPropertyTree> &_root)
|
|
|
+ : conn(_conn), timeoutMs(_timeoutMs), root(_root)
|
|
|
+ {
|
|
|
+ prevMode = conn->queryMode();
|
|
|
+ unsigned newMode = (prevMode & ~RTM_LOCKBASIC_MASK) | RTM_LOCK_WRITE;
|
|
|
+ conn->changeMode(RTM_LOCK_WRITE, timeoutMs);
|
|
|
+ }
|
|
|
+ ~CFileChangeWriteLock()
|
|
|
+ {
|
|
|
+ if (conn.get())
|
|
|
+ conn->changeMode(prevMode, timeoutMs);
|
|
|
+ }
|
|
|
+ IPropertyTree *detach(bool close)
|
|
|
+ {
|
|
|
+ Owned<IPropertyTree> detachedRoot = createPTreeFromIPT(root);
|
|
|
+ root.clear();
|
|
|
+ conn->close(close);
|
|
|
+ conn.clear();
|
|
|
+ return detachedRoot.getClear();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
static bool setFileProtectTree(IPropertyTree &p,const char *owner, bool protect)
|
|
|
{
|
|
|
bool ret = false;
|
|
@@ -2512,81 +2540,10 @@ protected:
|
|
|
root->removeProp("Attr");
|
|
|
return NULL;
|
|
|
}
|
|
|
-
|
|
|
- // Call this function *ONLY* from detach()
|
|
|
- // MORE: When the refactoring tips below get implemented, this method can go
|
|
|
- // And the appropriate sub methods can be created depending whether this is
|
|
|
- // a super-file or simply a file
|
|
|
- void doRemoveEntry(CDfsLogicalFileName &lfn, IUserDescriptor *user, unsigned timeoutms=INFINITE)
|
|
|
+ void updateFS(const CDfsLogicalFileName &lfn, unsigned timeoutMs)
|
|
|
{
|
|
|
- StringBuffer cname;
|
|
|
- lfn.getCluster(cname);
|
|
|
- DfsXmlBranchKind bkind;
|
|
|
- CFileConnectLock fconnlock;
|
|
|
- {
|
|
|
- IPropertyTree *froot=NULL;
|
|
|
- if (fconnlock.initany("doRemoveEntry", lfn, bkind, true, false, false, timeoutms))
|
|
|
- froot = fconnlock.queryRoot();
|
|
|
- if (!froot)
|
|
|
- ThrowStringException(-1, "Can't find SDS node for %s", lfn.get());
|
|
|
-
|
|
|
- // Remove Cluster from Logical file
|
|
|
- // MORE: Move this to a doRemoveCluster method
|
|
|
- if (cname.length()) {
|
|
|
- if (bkind==DXB_SuperFile)
|
|
|
- ThrowStringException(-1, "Trying to remove cluster %s from superfile %s",cname.str(),lfn.get());
|
|
|
-
|
|
|
- const char *group = froot->queryProp("@group");
|
|
|
- if (group&&(strcmp(group,cname.str())!=0)) { // see if only cluster (if it is remove entire)
|
|
|
- StringBuffer query;
|
|
|
- query.appendf("Cluster[@name=\"%s\"]",cname.str());
|
|
|
- IPropertyTree *t = froot->queryPropTree(query.str());
|
|
|
- if (t) {
|
|
|
- if (froot->removeTree(t))
|
|
|
- return;
|
|
|
- else
|
|
|
- ThrowStringException(-1, "Can't remove cluster %s from %s",cname.str(),lfn.get());
|
|
|
- }
|
|
|
- else
|
|
|
- ThrowStringException(-1, "Cluster %s not present in file %s",cname.str(),lfn.get());
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Remove SuperOwners from all sub files
|
|
|
- if (bkind==DXB_SuperFile) {
|
|
|
- Owned<IPropertyTreeIterator> iter = froot->getElements("SubFile");
|
|
|
- StringBuffer oquery;
|
|
|
- oquery.append("SuperOwner[@name=\"").append(lfn.get()).append("\"]");
|
|
|
- Owned<IMultiException> exceptions = MakeMultiException("CDelayedDelete::doRemoveEntry::SuperOwners");
|
|
|
- ForEach(*iter) {
|
|
|
- const char *name = iter->query().queryProp("@name");
|
|
|
- if (name&&*name) {
|
|
|
- CDfsLogicalFileName subfn;
|
|
|
- subfn.set(name);
|
|
|
- CFileConnectLock fconnlockSub;
|
|
|
- DfsXmlBranchKind subbkind;
|
|
|
- // MORE: Use CDistributedSuperFile::linkSuperOwner(false) - ie. unlink
|
|
|
- if (fconnlockSub.initany("CDelayedDelete::doRemoveEntry", subfn, subbkind, false, false, false, timeoutms))
|
|
|
- {
|
|
|
- IPropertyTree *subfroot = fconnlockSub.queryRoot();
|
|
|
- if (subfroot) {
|
|
|
- if (!subfroot->removeProp(oquery.str()))
|
|
|
- exceptions->append(*MakeStringException(-1, "CDelayedDelete::removeEntry: SubFile %s of %s not found for removal",name?name:"(NULL)",lfn.get()));
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- if (exceptions->ordinality())
|
|
|
- throw exceptions.getClear();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Remove from SDS and clean the lock
|
|
|
- fconnlock.remove();
|
|
|
- fconnlock.kill();
|
|
|
-
|
|
|
// Update the file system
|
|
|
- removeFileEmptyScope(lfn,timeoutms);
|
|
|
+ removeFileEmptyScope(lfn, timeoutMs);
|
|
|
// MORE: We shouldn't have to update all relationships if we had done a better job making sure
|
|
|
// that all correct relationships were properly cleaned up
|
|
|
queryDistributedFileDirectory().removeAllFileRelationships(lfn.get());
|
|
@@ -2944,7 +2901,6 @@ public:
|
|
|
class CDistributedFile: public CDistributedFileBase<IDistributedFile>
|
|
|
{
|
|
|
protected:
|
|
|
- Owned<IFileDescriptor> fdesc;
|
|
|
CDistributedFilePartArray parts; // use queryParts to access
|
|
|
CriticalSection sect;
|
|
|
StringAttr directory;
|
|
@@ -3001,6 +2957,142 @@ protected:
|
|
|
parts.item(i1++).clearDirty();
|
|
|
}
|
|
|
}
|
|
|
+ void detach(unsigned timeoutMs=INFINITE, bool removePhysicals=true)
|
|
|
+ {
|
|
|
+ // Removes either a cluster in case of multi cluster file or the whole File entry from DFS
|
|
|
+
|
|
|
+ assert(proplockcount == 0 && "CDistributedFile detach: Some properties are still locked");
|
|
|
+ assertex(!isAnon()); // not attached!
|
|
|
+
|
|
|
+ if (removePhysicals)
|
|
|
+ {
|
|
|
+ // Avoid removing physically when there is no physical representation
|
|
|
+ if (logicalName.isMulti() || logicalName.isExternal())
|
|
|
+ removePhysicals = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ StringBuffer clusterName;
|
|
|
+ Owned<IFileDescriptor> fileDescCopy;
|
|
|
+#ifdef EXTRA_LOGGING
|
|
|
+ PROGLOG("CDistributedFile::detach(%s)",logicalName.get());
|
|
|
+ LOGPTREE("CDistributedFile::detach root.1",root);
|
|
|
+#endif
|
|
|
+ {
|
|
|
+ CriticalBlock block(sect); // JCSMORE - not convinced this is still necessary
|
|
|
+ CFileChangeWriteLock writeLock(conn, timeoutMs, root);
|
|
|
+
|
|
|
+ logicalName.getCluster(clusterName);
|
|
|
+
|
|
|
+ // copy file descriptor before altered, used by physical file removal routines
|
|
|
+ if (removePhysicals)
|
|
|
+ {
|
|
|
+ MemoryBuffer mb;
|
|
|
+ Owned<IFileDescriptor> fdesc = getFileDescriptor(clusterName);
|
|
|
+ fdesc->serialize(mb);
|
|
|
+ fileDescCopy.setown(deserializeFileDescriptor(mb));
|
|
|
+ }
|
|
|
+
|
|
|
+ bool removeFile=true;
|
|
|
+ if (clusterName.length())
|
|
|
+ {
|
|
|
+ // Remove just cluster specified, unless it's the last, in which case detach below will remove File entry.
|
|
|
+ if (clusters.ordinality()>1)
|
|
|
+ {
|
|
|
+ if (removeCluster(clusterName.str()))
|
|
|
+ removeFile=false;
|
|
|
+ else
|
|
|
+ ThrowStringException(-1, "Cluster %s not present in file %s", clusterName.str(), logicalName.get());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // detach this IDistributeFile
|
|
|
+ root.setown(writeLock.detach(removeFile));
|
|
|
+ // NB: The file is now unlocked
|
|
|
+ if (removeFile)
|
|
|
+ updateFS(logicalName, timeoutMs);
|
|
|
+
|
|
|
+ logicalName.clear();
|
|
|
+ }
|
|
|
+ // NB: beyond unlock
|
|
|
+ if (removePhysicals)
|
|
|
+ {
|
|
|
+ CriticalBlock block(physicalChange);
|
|
|
+ Owned<IMultiException> exceptions = MakeMultiException("CDistributedFile::detach");
|
|
|
+ removePhysicalPartFiles(fileDescCopy, exceptions);
|
|
|
+ if (exceptions->ordinality())
|
|
|
+ throw exceptions.getClear();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ bool removePhysicalPartFiles(IFileDescriptor *fileDesc, IMultiException *mexcept)
|
|
|
+ {
|
|
|
+ if (logicalName.isExternal())
|
|
|
+ {
|
|
|
+ if (logicalName.isQuery())
|
|
|
+ return false;
|
|
|
+ throw MakeStringException(-1,"cannot remove an external file (%s)",logicalName.get());
|
|
|
+ }
|
|
|
+ if (logicalName.isForeign())
|
|
|
+ throw MakeStringException(-1,"cannot remove a foreign file (%s)",logicalName.get());
|
|
|
+
|
|
|
+ class casyncfor: public CAsyncFor
|
|
|
+ {
|
|
|
+ IFileDescriptor *fileDesc;
|
|
|
+ CriticalSection errcrit;
|
|
|
+ IMultiException *mexcept;
|
|
|
+ public:
|
|
|
+ bool ok;
|
|
|
+ bool islazy;
|
|
|
+ casyncfor(IFileDescriptor *_fileDesc, IMultiException *_mexcept)
|
|
|
+ {
|
|
|
+ fileDesc = _fileDesc;
|
|
|
+ ok = true;
|
|
|
+ islazy = false;
|
|
|
+ mexcept = _mexcept;
|
|
|
+ }
|
|
|
+ void Do(unsigned i)
|
|
|
+ {
|
|
|
+ IPartDescriptor *part = fileDesc->queryPart(i);
|
|
|
+ unsigned nc = part->numCopies();
|
|
|
+ for (unsigned copy = 0; copy < nc; copy++)
|
|
|
+ {
|
|
|
+ RemoteFilename rfn;
|
|
|
+ part->getFilename(copy, rfn);
|
|
|
+ Owned<IFile> partfile = createIFile(rfn);
|
|
|
+ StringBuffer eps;
|
|
|
+ try
|
|
|
+ {
|
|
|
+ unsigned start = msTick();
|
|
|
+ if (!partfile->remove()&&(copy==0)&&!islazy) // only warn about missing primary files
|
|
|
+ LOG(MCwarning, unknownJob, "Failed to remove file part %s from %s", partfile->queryFilename(),rfn.queryEndpoint().getUrlStr(eps).str());
|
|
|
+ else
|
|
|
+ {
|
|
|
+ unsigned t = msTick()-start;
|
|
|
+ if (t>5*1000)
|
|
|
+ LOG(MCwarning, unknownJob, "Removing %s from %s took %ds", partfile->queryFilename(), rfn.queryEndpoint().getUrlStr(eps).str(), t/1000);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (IException *e)
|
|
|
+ {
|
|
|
+ CriticalBlock block(errcrit);
|
|
|
+ if (mexcept)
|
|
|
+ mexcept->append(*e);
|
|
|
+ else
|
|
|
+ {
|
|
|
+ StringBuffer s("Failed to remove file part ");
|
|
|
+ s.append(partfile->queryFilename()).append(" from ");
|
|
|
+ rfn.queryEndpoint().getUrlStr(s);
|
|
|
+ EXCLOG(e, s.str());
|
|
|
+ e->Release();
|
|
|
+ }
|
|
|
+ ok = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } afor(fileDesc, mexcept);
|
|
|
+ afor.islazy = fileDesc->queryProperties().getPropBool("@lazy");
|
|
|
+ afor.For(fileDesc->numParts(),10,false,true);
|
|
|
+ return afor.ok;
|
|
|
+ }
|
|
|
|
|
|
protected: friend class CDistributedFilePart;
|
|
|
CDistributedFilePartArray &queryParts()
|
|
@@ -3283,7 +3375,7 @@ public:
|
|
|
saveClusters();
|
|
|
}
|
|
|
|
|
|
- void removeCluster(const char *clustername)
|
|
|
+ bool removeCluster(const char *clustername)
|
|
|
{
|
|
|
CClustersLockedSection cls(CDistributedFileBase<IDistributedFile>::logicalName);
|
|
|
reloadClusters();
|
|
@@ -3293,7 +3385,9 @@ public:
|
|
|
throw MakeStringException(-1,"CFileClusterOwner::removeCluster cannot remove sole cluster %s",clustername);
|
|
|
clusters.remove(i);
|
|
|
saveClusters();
|
|
|
+ return true;
|
|
|
}
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
void setPreferredClusters(const char *clusterlist)
|
|
@@ -3562,7 +3656,6 @@ public:
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
-private:
|
|
|
/*
|
|
|
* Internal method (not in IDistributedFile interface) that is used
|
|
|
* when renaming files (so don't delete the physical representation).
|
|
@@ -3572,155 +3665,16 @@ private:
|
|
|
*
|
|
|
* See removeLogical()
|
|
|
*/
|
|
|
-#ifdef _USE_CPPUNIT
|
|
|
public:
|
|
|
-#endif
|
|
|
void detachLogical(unsigned timeoutms=INFINITE)
|
|
|
{
|
|
|
detach(timeoutms, false);
|
|
|
}
|
|
|
|
|
|
public:
|
|
|
-
|
|
|
- void detach(unsigned timeoutms=INFINITE, bool removePhysicalParts=true)
|
|
|
+ virtual void detach(unsigned timeoutMs=INFINITE)
|
|
|
{
|
|
|
- assert(proplockcount == 0 && "CDistributedFile detach: Some properties are still locked");
|
|
|
- assertex(!isAnon()); // not attached!
|
|
|
-
|
|
|
- // If cluster name was passed via query (filename@cluster), try to find it
|
|
|
- StringBuffer clustername;
|
|
|
- logicalName.getCluster(clustername);
|
|
|
-
|
|
|
- // Avoid removing physically when there is no physical representation
|
|
|
- if (logicalName.isMulti() || logicalName.isExternal())
|
|
|
- removePhysicalParts = false;
|
|
|
-
|
|
|
- // Clean up file and remove from SDS only if this is the last
|
|
|
- // cluster it belongs to, since we should be able to still remove
|
|
|
- // the other clusters' files. Or if there are no clusters.
|
|
|
- if ((clustername.length()==0) /* no cluster passed - ie. detach all */
|
|
|
- ||((findCluster(clustername.str())==0)&&(numClusters()==1))) /* cluster is first, and no other clusters */
|
|
|
- {
|
|
|
- CriticalBlock block (sect);
|
|
|
- MemoryBuffer mb;
|
|
|
-#ifdef EXTRA_LOGGING
|
|
|
- PROGLOG("CDistributedFile::detach(%s)",logicalName.get());
|
|
|
- LOGPTREE("CDistributedFile::detach root.1",root);
|
|
|
-#endif
|
|
|
- root->serialize(mb);
|
|
|
- conn.clear();
|
|
|
- root.setown(createPTree(mb));
|
|
|
- CDfsLogicalFileName lname;
|
|
|
- lname.set(logicalName);
|
|
|
- logicalName.clear();
|
|
|
-#ifdef EXTRA_LOGGING
|
|
|
- LOGPTREE("CDistributedFile::detach root.2",root);
|
|
|
-#endif
|
|
|
- // Remove from SDS
|
|
|
- doRemoveEntry(lname,udesc,timeoutms);
|
|
|
- // Make sure we remove *all* physical instances
|
|
|
- clustername.clear();
|
|
|
- }
|
|
|
-
|
|
|
- // Remove parts, physically
|
|
|
- if (removePhysicalParts)
|
|
|
- {
|
|
|
- CriticalBlock block(physicalChange);
|
|
|
- Owned<IMultiException> exceptions = MakeMultiException("CDistributedFile::detach");
|
|
|
- removePhysicalPartFiles(clustername.str(),exceptions);
|
|
|
- if (exceptions->ordinality())
|
|
|
- throw exceptions.getClear();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- bool removePhysicalPartFiles(const char *cluster,IMultiException *mexcept)
|
|
|
- {
|
|
|
- Owned<IGroup> grpfilter;
|
|
|
- if (cluster&&*cluster) {
|
|
|
- unsigned cn = findCluster(cluster);
|
|
|
- if (cn==NotFound)
|
|
|
- return false;
|
|
|
- if (clusters.ordinality()==0)
|
|
|
- cluster = NULL; // cannot delete last cluster
|
|
|
- else
|
|
|
- grpfilter.setown(clusters.getGroup(cn));
|
|
|
- }
|
|
|
- if (logicalName.isExternal()) {
|
|
|
- if (logicalName.isQuery())
|
|
|
- return false;
|
|
|
- throw MakeStringException(-1,"cannot remove an external file (%s)",logicalName.get());
|
|
|
- }
|
|
|
- if (logicalName.isForeign())
|
|
|
- throw MakeStringException(-1,"cannot remove a foreign file (%s)",logicalName.get());
|
|
|
-
|
|
|
- unsigned width = numParts();
|
|
|
- CriticalSection errcrit;
|
|
|
- class casyncfor: public CAsyncFor
|
|
|
- {
|
|
|
- IDistributedFile *file;
|
|
|
- CriticalSection &errcrit;
|
|
|
- IMultiException *mexcept;
|
|
|
- unsigned width;
|
|
|
- IGroup *grpfilter;
|
|
|
- public:
|
|
|
- bool ok;
|
|
|
- bool islazy;
|
|
|
- casyncfor(IDistributedFile *_file,unsigned _width,IGroup *_grpfilter,IMultiException *_mexcept,CriticalSection &_errcrit)
|
|
|
- : errcrit(_errcrit)
|
|
|
- {
|
|
|
- file = _file;
|
|
|
- ok = true;
|
|
|
- islazy = false;
|
|
|
- mexcept = _mexcept;
|
|
|
- width = _width;
|
|
|
- grpfilter = _grpfilter;
|
|
|
- }
|
|
|
- void Do(unsigned i)
|
|
|
- {
|
|
|
- Owned<IDistributedFilePart> part = file->getPart(i);
|
|
|
- unsigned nc = part->numCopies();
|
|
|
- for (unsigned copy = 0; copy < nc; copy++)
|
|
|
- {
|
|
|
- RemoteFilename rfn;
|
|
|
- part->getFilename(rfn,copy);
|
|
|
- if (grpfilter&&(grpfilter->rank(rfn.queryEndpoint())==RANK_NULL))
|
|
|
- continue;
|
|
|
- Owned<IFile> partfile = createIFile(rfn);
|
|
|
- StringBuffer eps;
|
|
|
- try
|
|
|
- {
|
|
|
- unsigned start = msTick();
|
|
|
- if (!partfile->remove()&&(copy==0)&&!islazy) // only warn about missing primary files
|
|
|
- LOG(MCwarning, unknownJob, "Failed to remove file part %s from %s", partfile->queryFilename(),rfn.queryEndpoint().getUrlStr(eps).str());
|
|
|
- else {
|
|
|
- unsigned t = msTick()-start;
|
|
|
- if (t>5*1000)
|
|
|
- LOG(MCwarning, unknownJob, "Removing %s from %s took %ds", partfile->queryFilename(), rfn.queryEndpoint().getUrlStr(eps).str(), t/1000);
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
- catch (IException *e)
|
|
|
- {
|
|
|
- CriticalBlock block(errcrit);
|
|
|
- if (mexcept)
|
|
|
- mexcept->append(*e);
|
|
|
- else {
|
|
|
- StringBuffer s("Failed to remove file part ");
|
|
|
- s.append(partfile->queryFilename()).append(" from ");
|
|
|
- rfn.queryEndpoint().getUrlStr(s);
|
|
|
- EXCLOG(e, s.str());
|
|
|
- e->Release();
|
|
|
- }
|
|
|
- ok = false;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- } afor(this,width,grpfilter,mexcept,errcrit);
|
|
|
- afor.islazy = queryAttributes().getPropInt("@lazy")!=0;
|
|
|
- afor.For(width,10,false,true);
|
|
|
- if (cluster&&*cluster)
|
|
|
- removeCluster(cluster);
|
|
|
- return afor.ok;
|
|
|
+ detach(timeoutMs, true);
|
|
|
}
|
|
|
|
|
|
bool existsPhysicalPartFiles(unsigned short port)
|
|
@@ -3833,7 +3787,7 @@ public:
|
|
|
if (newbasedir)
|
|
|
diroverride = newbasedir;
|
|
|
|
|
|
- const char *myBase = queryBaseDirectory(false,os);
|
|
|
+ const char *myBase = queryBaseDirectory(0, os);
|
|
|
StringBuffer baseDir, newPath;
|
|
|
makePhysicalPartName(logicalName.get(), 0, 0, newPath, false, os, diroverride);
|
|
|
if (!getBase(directory, newPath, baseDir))
|
|
@@ -4607,6 +4561,37 @@ protected:
|
|
|
int interleaved; // 0 not interleaved, 1 interleaved old, 2 interleaved new
|
|
|
IArrayOf<IDistributedFile> subfiles;
|
|
|
|
|
|
+ void clearSuperOwners(unsigned timeoutMs)
|
|
|
+ {
|
|
|
+ Owned<IPropertyTreeIterator> iter = root->getElements("SubFile");
|
|
|
+ StringBuffer oquery;
|
|
|
+ oquery.append("SuperOwner[@name=\"").append(logicalName.get()).append("\"]");
|
|
|
+ Owned<IMultiException> exceptions = MakeMultiException("CDelayedDelete::doRemoveEntry::SuperOwners");
|
|
|
+ ForEach(*iter)
|
|
|
+ {
|
|
|
+ const char *name = iter->query().queryProp("@name");
|
|
|
+ if (name&&*name)
|
|
|
+ {
|
|
|
+ CDfsLogicalFileName subfn;
|
|
|
+ subfn.set(name);
|
|
|
+ CFileConnectLock fconnlockSub;
|
|
|
+ DfsXmlBranchKind subbkind;
|
|
|
+ // MORE: Use CDistributedSuperFile::linkSuperOwner(false) - ie. unlink
|
|
|
+ if (fconnlockSub.initany("CDelayedDelete::doRemoveEntry", subfn, subbkind, false, false, false, timeoutMs))
|
|
|
+ {
|
|
|
+ IPropertyTree *subfroot = fconnlockSub.queryRoot();
|
|
|
+ if (subfroot)
|
|
|
+ {
|
|
|
+ if (!subfroot->removeProp(oquery.str()))
|
|
|
+ exceptions->append(*MakeStringException(-1, "CDelayedDelete::removeEntry: SubFile %s of %s not found for removal",name?name:"(NULL)", logicalName.get()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (exceptions->ordinality())
|
|
|
+ throw exceptions.getClear();
|
|
|
+ }
|
|
|
+
|
|
|
static StringBuffer &getSubPath(StringBuffer &path,unsigned idx)
|
|
|
{
|
|
|
return path.append("SubFile[@num=\"").append(idx+1).append("\"]");
|
|
@@ -5124,8 +5109,6 @@ public:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
void attach(const char *_logicalname,IUserDescriptor *user)
|
|
|
{
|
|
|
// will need more thought but this gives limited support for anon
|
|
@@ -5145,32 +5128,22 @@ public:
|
|
|
root.setown(conn->getRoot());
|
|
|
}
|
|
|
|
|
|
- void detach(unsigned timeoutms=INFINITE, bool removePhysicalParts=true)
|
|
|
+ void detach(unsigned timeoutMs=INFINITE)
|
|
|
{
|
|
|
// will need more thought but this gives limited support for anon
|
|
|
if (isAnon())
|
|
|
return;
|
|
|
assertex(conn.get()); // must be attached
|
|
|
- CriticalBlock block (sect);
|
|
|
+ CriticalBlock block(sect);
|
|
|
checkModify("CDistributedSuperFile::detach");
|
|
|
subfiles.kill();
|
|
|
- MemoryBuffer mb;
|
|
|
- root->serialize(mb);
|
|
|
- root.clear();
|
|
|
- conn.clear();
|
|
|
- root.setown(createPTree(mb));
|
|
|
- CDfsLogicalFileName lname;
|
|
|
- lname.set(logicalName);
|
|
|
- logicalName.clear();
|
|
|
|
|
|
// Remove from SDS
|
|
|
- doRemoveEntry(lname,udesc,timeoutms);
|
|
|
- }
|
|
|
-
|
|
|
- bool removePhysicalPartFiles(const char *clustername,IMultiException *mexcept)
|
|
|
- {
|
|
|
- throw MakeStringException(-1,"removePhysicalPartFiles not supported for SuperFiles");
|
|
|
- return false;
|
|
|
+ CFileChangeWriteLock writeLock(conn, timeoutMs, root);
|
|
|
+ clearSuperOwners(timeoutMs);
|
|
|
+ root.setown(writeLock.detach(true));
|
|
|
+ updateFS(logicalName, timeoutMs);
|
|
|
+ logicalName.clear();
|
|
|
}
|
|
|
|
|
|
bool existsPhysicalPartFiles(unsigned short port)
|
|
@@ -5842,14 +5815,16 @@ public:
|
|
|
subfiles.item(0).addCluster(clustername,mspec);
|
|
|
}
|
|
|
|
|
|
- virtual void removeCluster(const char *clustername)
|
|
|
+ virtual bool removeCluster(const char *clustername)
|
|
|
{
|
|
|
+ bool clusterRemoved=false;
|
|
|
CriticalBlock block (sect);
|
|
|
clusterscache.clear();
|
|
|
ForEachItemIn(i,subfiles) {
|
|
|
IDistributedFile &f=subfiles.item(i);
|
|
|
- f.removeCluster(clustername);
|
|
|
+ clusterRemoved |= f.removeCluster(clustername);
|
|
|
}
|
|
|
+ return clusterRemoved;
|
|
|
}
|
|
|
|
|
|
void setPreferredClusters(const char *clusters)
|
|
@@ -6316,16 +6291,50 @@ public:
|
|
|
|
|
|
#define GROUP_CACHE_INTERVAL (1000*60)
|
|
|
|
|
|
+static const char *translateGroupType(GroupType groupType)
|
|
|
+{
|
|
|
+ switch (groupType)
|
|
|
+ {
|
|
|
+ case grp_thor:
|
|
|
+ return "Thor";
|
|
|
+ case grp_roxie:
|
|
|
+ return "Roxie";
|
|
|
+ case grp_roxiefarm:
|
|
|
+ return "RoxieFarm";
|
|
|
+ case grp_hthor:
|
|
|
+ return "hthor";
|
|
|
+ default:
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static GroupType translateGroupType(const char *groupType)
|
|
|
+{
|
|
|
+ if (!groupType)
|
|
|
+ return grp_unknown;
|
|
|
+ if (strieq(groupType, "Thor"))
|
|
|
+ return grp_thor;
|
|
|
+ else if (strieq(groupType, "Roxie"))
|
|
|
+ return grp_roxie;
|
|
|
+ else if (strieq(groupType, "RoxieFarm"))
|
|
|
+ return grp_roxiefarm;
|
|
|
+ else if (strieq(groupType, "hthor"))
|
|
|
+ return grp_hthor;
|
|
|
+ else
|
|
|
+ return grp_unknown;
|
|
|
+}
|
|
|
+
|
|
|
class CNamedGroupCacheEntry: public CInterface
|
|
|
{
|
|
|
public:
|
|
|
Linked<IGroup> group;
|
|
|
StringAttr name;
|
|
|
- StringAttr groupdir;
|
|
|
+ StringAttr groupDir;
|
|
|
unsigned cachedtime;
|
|
|
+ GroupType groupType;
|
|
|
|
|
|
- CNamedGroupCacheEntry(IGroup *_group, const char *_name, const char *_dir)
|
|
|
- : group(_group), name(_name), groupdir(_dir)
|
|
|
+ CNamedGroupCacheEntry(IGroup *_group, const char *_name, const char *_dir, GroupType _groupType)
|
|
|
+ : group(_group), name(_name), groupDir(_dir), groupType(_groupType)
|
|
|
{
|
|
|
cachedtime = msTick();
|
|
|
}
|
|
@@ -6345,7 +6354,7 @@ public:
|
|
|
defaultTimeout = INFINITE;
|
|
|
}
|
|
|
|
|
|
- IGroup *dolookup(const char *logicalgroupname,IRemoteConnection *conn, StringBuffer *dirret)
|
|
|
+ IGroup *dolookup(const char *logicalgroupname,IRemoteConnection *conn, StringBuffer *dirret, GroupType &groupType)
|
|
|
{
|
|
|
SocketEndpointArray epa;
|
|
|
StringBuffer gname(logicalgroupname);
|
|
@@ -6396,6 +6405,7 @@ public:
|
|
|
logicalgroupname = gname.str();
|
|
|
}
|
|
|
StringAttr groupdir;
|
|
|
+ GroupType type;
|
|
|
bool cached = false;
|
|
|
unsigned timeNow = msTick();
|
|
|
{
|
|
@@ -6413,12 +6423,14 @@ public:
|
|
|
if (range.length()==0)
|
|
|
{
|
|
|
if (dirret)
|
|
|
- dirret->append(entry.groupdir);
|
|
|
+ dirret->append(entry.groupDir);
|
|
|
+ groupType = entry.groupType;
|
|
|
return entry.group.getLink();
|
|
|
}
|
|
|
// there is a range so copy to epa
|
|
|
entry.group->getSocketEndpoints(epa);
|
|
|
- groupdir.set(entry.groupdir);
|
|
|
+ groupdir.set(entry.groupDir);
|
|
|
+ type = entry.groupType;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
@@ -6432,7 +6444,7 @@ public:
|
|
|
s+=2;
|
|
|
if (*s) {
|
|
|
Owned<INode> dali = createINode(eps.str());
|
|
|
- if (!dali || !getRemoteGroup(dali, s, FOREIGN_DALI_TIMEOUT, groupdir, epa))
|
|
|
+ if (!dali || !getRemoteGroup(dali, s, FOREIGN_DALI_TIMEOUT, groupdir, type, epa))
|
|
|
return NULL;
|
|
|
}
|
|
|
}
|
|
@@ -6454,6 +6466,7 @@ public:
|
|
|
if (!pt)
|
|
|
return NULL;
|
|
|
groupdir.set(pt->queryProp("@dir"));
|
|
|
+ type = translateGroupType(pt->queryProp("@kind"));
|
|
|
Owned<IPropertyTreeIterator> pe2 = pt->getElements("Node");
|
|
|
ForEach(*pe2) {
|
|
|
SocketEndpoint ep(pe2->query().queryProp("@ip"));
|
|
@@ -6464,7 +6477,7 @@ public:
|
|
|
if (!cached)
|
|
|
{
|
|
|
CriticalBlock block(cachesect);
|
|
|
- cache.append(*new CNamedGroupCacheEntry(ret, gname, groupdir));
|
|
|
+ cache.append(*new CNamedGroupCacheEntry(ret, gname, groupdir, type));
|
|
|
}
|
|
|
if (range.length())
|
|
|
{
|
|
@@ -6516,17 +6529,19 @@ public:
|
|
|
}
|
|
|
if (dirret)
|
|
|
dirret->append(groupdir);
|
|
|
+ groupType = type;
|
|
|
return ret.getClear();
|
|
|
}
|
|
|
|
|
|
IGroup *lookup(const char *logicalgroupname)
|
|
|
{
|
|
|
- return dolookup(logicalgroupname,NULL,NULL);
|
|
|
+ GroupType dummy;
|
|
|
+ return dolookup(logicalgroupname, NULL, NULL, dummy);
|
|
|
}
|
|
|
|
|
|
- IGroup *lookup(const char *logicalgroupname, StringBuffer &dir)
|
|
|
+ IGroup *lookup(const char *logicalgroupname, StringBuffer &dir, GroupType &groupType)
|
|
|
{
|
|
|
- return dolookup(logicalgroupname,NULL,&dir);
|
|
|
+ return dolookup(logicalgroupname, NULL, &dir, groupType);
|
|
|
}
|
|
|
|
|
|
INamedGroupIterator *getIterator()
|
|
@@ -6593,7 +6608,7 @@ public:
|
|
|
lname.append(name);
|
|
|
}
|
|
|
|
|
|
- void add(const char *logicalgroupname,IGroup *group,bool cluster,const char *dir)
|
|
|
+ void add(const char *logicalgroupname, IGroup *group, bool cluster, const char *dir, GroupType groupType)
|
|
|
{
|
|
|
StringBuffer name(logicalgroupname);
|
|
|
name.toLowerCase();
|
|
@@ -6607,13 +6622,13 @@ public:
|
|
|
CriticalBlock block(cachesect);
|
|
|
cache.kill();
|
|
|
if (group)
|
|
|
- cache.append(*new CNamedGroupCacheEntry(group, name.str(), dir));
|
|
|
+ cache.append(*new CNamedGroupCacheEntry(group, name.str(), dir, groupType));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void remove(const char *logicalgroupname)
|
|
|
{
|
|
|
- add(logicalgroupname,NULL,false,NULL);
|
|
|
+ add(logicalgroupname, NULL, false, NULL, grp_unknown);
|
|
|
}
|
|
|
|
|
|
bool find(IGroup *grp, StringBuffer &gname, bool add)
|
|
@@ -6685,7 +6700,8 @@ public:
|
|
|
}
|
|
|
|
|
|
private:
|
|
|
- bool getRemoteGroup(const INode *foreigndali, const char *gname, unsigned foreigndalitimeout, StringAttr &groupdir, SocketEndpointArray &epa)
|
|
|
+ bool getRemoteGroup(const INode *foreigndali, const char *gname, unsigned foreigndalitimeout,
|
|
|
+ StringAttr &groupdir, GroupType &type, SocketEndpointArray &epa)
|
|
|
{
|
|
|
StringBuffer lcname(gname);
|
|
|
gname = lcname.trim().toLowerCase().str();
|
|
@@ -6712,6 +6728,7 @@ private:
|
|
|
Owned<IPropertyTree> pt = createPTree(mb);
|
|
|
Owned<IPropertyTreeIterator> pe = pt->getElements("Node");
|
|
|
groupdir.set(pt->queryProp("@dir"));
|
|
|
+ type = translateGroupType(pt->queryProp("@kind"));
|
|
|
ForEach(*pe) {
|
|
|
SocketEndpoint ep(pe->query().queryProp("@ip"));
|
|
|
epa.append(ep);
|
|
@@ -6733,7 +6750,8 @@ bool CNamedGroupIterator::match()
|
|
|
const char *name = pe->query().queryProp("@name");
|
|
|
if (!name||!*name)
|
|
|
return false;
|
|
|
- Owned<IGroup> lgrp = groupStore->dolookup(name,conn,NULL);
|
|
|
+ GroupType dummy;
|
|
|
+ Owned<IGroup> lgrp = groupStore->dolookup(name, conn, NULL, dummy);
|
|
|
if (lgrp) {
|
|
|
if (exactmatch)
|
|
|
return lgrp->equals(matchgroup);
|
|
@@ -7428,7 +7446,8 @@ private:
|
|
|
ClusterPartDiskMapSpec mspec = file->queryPartDiskMapping(0);
|
|
|
// Unlock the old file
|
|
|
unlock();
|
|
|
- file->detach(INFINITE, false); // don't delete physicals, now used by newFile
|
|
|
+ CDistributedFile *_file = dynamic_cast<CDistributedFile *>(file.get());
|
|
|
+ _file->detachLogical(INFINITE); // don't delete physicals, now used by newFile
|
|
|
transaction->clearFile(file); // no long used in transaction
|
|
|
newFile->addCluster(newcluster.str(),mspec);
|
|
|
parent->fixDates(newFile);
|
|
@@ -8159,7 +8178,6 @@ class CInitGroups
|
|
|
grp->setProp("@name", name);
|
|
|
}
|
|
|
|
|
|
- enum GroupType { grp_thor, grp_thorspares, grp_roxie, grp_roxiefarm, grp_hthor };
|
|
|
IGroup *getGroupFromCluster(GroupType groupType, IPropertyTree &cluster)
|
|
|
{
|
|
|
SocketEndpointArray eps;
|
|
@@ -8206,24 +8224,20 @@ class CInitGroups
|
|
|
{
|
|
|
Owned<IPropertyTreeIterator> channels;
|
|
|
channels.setown(node.getElements("RoxieChannel"));
|
|
|
- unsigned j = 0;
|
|
|
- unsigned mindrive = (unsigned)-1;
|
|
|
+ unsigned thisNodePrimaryChannel = 0;
|
|
|
ForEach(*channels) {
|
|
|
- unsigned k = channels->query().getPropInt("@number");
|
|
|
- const char * dir = channels->query().queryProp("@dataDirectory");
|
|
|
- unsigned d = dir?getPathDrive(dir):0;
|
|
|
- if (d<mindrive) {
|
|
|
- j = k;
|
|
|
- mindrive = d;
|
|
|
- }
|
|
|
+ unsigned channel = channels->query().getPropInt("@number");
|
|
|
+ unsigned level = channels->query().getPropInt("@level", 0);
|
|
|
+ if (level == 0) // level 0 means primary copy
|
|
|
+ thisNodePrimaryChannel = channel;
|
|
|
}
|
|
|
- if (j==0) {
|
|
|
+ if (thisNodePrimaryChannel==0) {
|
|
|
ERRLOG("Cannot construct roxie cluster %s, no channel for node",cluster.queryProp("@name"));
|
|
|
return NULL;
|
|
|
}
|
|
|
- while (eps.ordinality()<j)
|
|
|
+ while (eps.ordinality()<thisNodePrimaryChannel)
|
|
|
eps.append(nullep);
|
|
|
- eps.item(j-1) = ep;
|
|
|
+ eps.item(thisNodePrimaryChannel-1) = ep;
|
|
|
break;
|
|
|
}
|
|
|
case grp_thor:
|
|
@@ -8333,13 +8347,9 @@ class CInitGroups
|
|
|
realCluster = false;
|
|
|
break;
|
|
|
case grp_roxie:
|
|
|
- defDir = cluster.queryProp("@slaveDataDir");
|
|
|
- if (!defDir||!*defDir)
|
|
|
- defDir = cluster.queryProp("@baseDataDir");
|
|
|
gname.append(cluster.queryProp("@name"));
|
|
|
break;
|
|
|
case grp_roxiefarm:
|
|
|
- defDir = cluster.queryProp("@dataDirectory");
|
|
|
break;
|
|
|
default:
|
|
|
throwUnexpected();
|