示例#1
0
int Client::list(const string& path, vector<SNode>& attr)
{
   string revised_path = Metadata::revisePath(path);

   SectorMsg msg;
   msg.resize(65536);
   msg.setType(101);
   msg.setKey(m_iKey);
   msg.setData(0, revised_path.c_str(), revised_path.length() + 1);

   Address serv;
   m_Routing.lookup(revised_path, serv);
   login(serv.m_strIP, serv.m_iPort);

   if (m_GMP.rpc(serv.m_strIP.c_str(), serv.m_iPort, &msg, &msg) < 0)
      return SectorError::E_CONNECTION;

   if (msg.getType() < 0)
      return *(int32_t*)(msg.getData());

   string filelist = msg.getData();

   unsigned int s = 0;
   while (s < filelist.length())
   {
      int t = filelist.find(';', s);
      SNode sn;
      sn.deserialize(filelist.substr(s, t - s).c_str());
      attr.insert(attr.end(), sn);
      s = t + 1;
   }

   return attr.size();
}
示例#2
0
int Client::stat(const string& path, SNode& attr)
{
   string revised_path = Metadata::revisePath(path);

   SectorMsg msg;
   msg.resize(65536);
   msg.setType(102);
   msg.setKey(m_iKey);
   msg.setData(0, revised_path.c_str(), revised_path.length() + 1);

   Address serv;
   m_Routing.lookup(revised_path, serv);
   login(serv.m_strIP, serv.m_iPort);

   if (m_GMP.rpc(serv.m_strIP.c_str(), serv.m_iPort, &msg, &msg) < 0)
      return SectorError::E_CONNECTION;

   if (msg.getType() < 0)
      return *(int32_t*)(msg.getData());

   attr.deserialize(msg.getData());

   int n = (msg.m_iDataLength - SectorMsg::m_iHdrSize - 128) / 68;
   char* al = msg.getData() + 128;

   for (int i = 0; i < n; ++ i)
   {
      Address addr;
      addr.m_strIP = al + 68 * i;
      addr.m_iPort = *(int32_t*)(al + 68 * i + 64);
      attr.m_sLocation.insert(addr);
   }

   // check local cache: updated files may not be sent to the master yet
   m_StatCache.stat(path, attr);

   return 0;
}
示例#3
0
DWORD WINAPI Slave::copy(LPVOID p)
#endif
{
   Slave* self = ((Param3*)p)->serv_instance;
   int transid = ((Param3*)p)->transid;
   int dir = ((Param3*)p)->dir;
   string src = ((Param3*)p)->src;
   string dst = ((Param3*)p)->dst;
   string master_ip = ((Param3*)p)->master_ip;
   int master_port = ((Param3*)p)->master_port;
   delete (Param3*)p;

   if (src.c_str()[0] == '\0')
      src = "/" + src;
   if (dst.c_str()[0] == '\0')
      dst = "/" + dst;

   bool success = true;

   queue<string> tr;	// files to be replicated
   queue<string> td;	// directories to be explored

   if (dir > 0)
      td.push(src);
   else
      tr.push(src);

   while (!td.empty())
   {
      // If the file to be replicated is a directory, recursively list all files first

      string src_path = td.front();
      td.pop();

      // try list this path
      SectorMsg msg;
      msg.setType(101);
      msg.setKey(0);
      msg.setData(0, src_path.c_str(), src_path.length() + 1);

      Address addr;
      self->m_Routing.lookup(src_path, addr);

      if (self->m_GMP.rpc(addr.m_strIP.c_str(), addr.m_iPort, &msg, &msg) < 0)
      {
         success = false;
         break;
      }

      // the master only returns positive if this is a directory
      if (msg.getType() >= 0)
      {
         // if this is a directory, create it, and put all files and sub-directories into the queue of files to be copied

         // create a local dir
         string dst_path = dst;
         if (src != src_path)
            dst_path += "/" + src_path.substr(src.length() + 1, src_path.length() - src.length() - 1);

         //create at .tmp first, then move to real location
         self->createDir(string(".tmp") + dst_path);

         string filelist = msg.getData();
         unsigned int s = 0;
         while (s < filelist.length())
         {
            int t = filelist.find(';', s);
            SNode sn;
            sn.deserialize(filelist.substr(s, t - s).c_str());
            if (sn.m_bIsDir)
               td.push(src_path + "/" + sn.m_strName);
            else
               tr.push(src_path + "/" + sn.m_strName);
            s = t + 1;
         }

         continue;
      }
   }

   while (!tr.empty())
   {
      string src_path = tr.front();
      tr.pop();

      SNode tmp;
      if (self->m_pLocalFile->lookup(src_path.c_str(), tmp) >= 0)
      {
         //if file is local, copy directly
         //note that in this case, src != dst, therefore this is a regular "cp" command, not a system replication

         //IMPORTANT!!!
         //local files must be read directly from local disk, and cannot be read via datachn due to its limitation

         string dst_path = dst;
         if (src != src_path)
            dst_path += "/" + src_path.substr(src.length() + 1, src_path.length() - src.length() - 1);

         //copy to .tmp first, then move to real location
         self->createDir(string(".tmp") + dst_path.substr(0, dst_path.rfind('/')));
         LocalFS::copy(self->m_strHomeDir + src_path, self->m_strHomeDir + ".tmp" + dst_path);
      }
      else
      {
         // open the file and copy it to local
         SectorMsg msg;
         msg.setType(110);
         msg.setKey(0);

         int32_t mode = SF_MODE::READ;
         msg.setData(0, (char*)&mode, 4);
         int32_t localport = self->m_DataChn.getPort();
         msg.setData(4, (char*)&localport, 4);
         int32_t len_name = src_path.length() + 1;
         msg.setData(8, (char*)&len_name, 4);
         msg.setData(12, src_path.c_str(), len_name);
         int32_t len_opt = 0;
         msg.setData(12 + len_name, (char*)&len_opt, 4);

         Address addr;
         self->m_Routing.lookup(src_path, addr);

         if ((self->m_GMP.rpc(addr.m_strIP.c_str(), addr.m_iPort, &msg, &msg) < 0) || (msg.getType() < 0))
         {
            success = false;
            break;
         }

         int32_t session = *(int32_t*)msg.getData();
         int64_t size = *(int64_t*)(msg.getData() + 4);
         time_t ts = *(int64_t*)(msg.getData() + 12);

         string ip = msg.getData() + 24;
         int32_t port = *(int32_t*)(msg.getData() + 64 + 24);

         if (!self->m_DataChn.isConnected(ip, port))
         {
            if (self->m_DataChn.connect(ip, port) < 0)
            {
               success = false;
               break;
            }
         }

         // download command: 3
         int32_t cmd = 3;
         self->m_DataChn.send(ip, port, session, (char*)&cmd, 4);

         int64_t offset = 0;
         self->m_DataChn.send(ip, port, session, (char*)&offset, 8);

         int response = -1;
         if ((self->m_DataChn.recv4(ip, port, session, response) < 0) || (-1 == response))
         {
            success = false;
            break;
         }

         string dst_path = dst;
         if (src != src_path)
            dst_path += "/" + src_path.substr(src.length() + 1, src_path.length() - src.length() - 1);

         //copy to .tmp first, then move to real location
         self->createDir(string(".tmp") + dst_path.substr(0, dst_path.rfind('/')));

         fstream ofs;
         ofs.open((self->m_strHomeDir + ".tmp" + dst_path).c_str(), ios::out | ios::binary | ios::trunc);

         int64_t unit = 64000000; //send 64MB each time
         int64_t torecv = size;
         int64_t recd = 0;
         while (torecv > 0)
         {
            int64_t block = (torecv < unit) ? torecv : unit;
            if (self->m_DataChn.recvfile(ip, port, session, ofs, offset + recd, block) < 0)
            {
               success = false;
               break;
            }

            recd += block;
            torecv -= block;
         }

         ofs.close();

         // update total received data size
         self->m_SlaveStat.updateIO(ip, size, +SlaveStat::SYS_IN);

         cmd = 5;
         self->m_DataChn.send(ip, port, session, (char*)&cmd, 4);
         self->m_DataChn.recv4(ip, port, session, cmd);

         if (src == dst)
         {
            //utime: update timestamp according to the original copy, for replica only; files created by "cp" have new timestamp
            utimbuf ut;
            ut.actime = ts;
            ut.modtime = ts;
            utime((self->m_strHomeDir + ".tmp" + dst_path).c_str(), &ut);
         }
      }
   }

   if (success)
   {
      // move from temporary dir to the real dir when the copy is completed
      self->createDir(dst.substr(0, dst.rfind('/')));
      LocalFS::rename(self->m_strHomeDir + ".tmp" + dst, self->m_strHomeDir + dst);

      // if the file has been modified during the replication, remove this replica
      int32_t type = (src == dst) ? +FileChangeType::FILE_UPDATE_REPLICA : +FileChangeType::FILE_UPDATE_NEW;
      if (self->report(master_ip, master_port, transid, dst, type) < 0)
         LocalFS::erase(self->m_strHomeDir + dst);
   }
   else
   {
      // failed, remove all temporary files
      LocalFS::erase(self->m_strHomeDir + ".tmp" + dst);
      self->report(master_ip, master_port, transid, "", +FileChangeType::FILE_UPDATE_NO);
   }

   // clear this transaction
   self->m_TransManager.updateSlave(transid, self->m_iSlaveID);

   return NULL;
}
示例#4
0
void* Slave::copy(void* p)
{
   Slave* self = ((Param3*)p)->serv_instance;
   int transid = ((Param3*)p)->transid;
   string src = ((Param3*)p)->src;
   string dst = ((Param3*)p)->dst;
   string master_ip = ((Param3*)p)->master_ip;
   int master_port = ((Param3*)p)->master_port;
   delete (Param3*)p;

   if (src.c_str()[0] == '\0')
      src = "/" + src;
   if (dst.c_str()[0] == '\0')
      dst = "/" + dst;

   SNode tmp;
   if (self->m_pLocalFile->lookup(src.c_str(), tmp) >= 0)
   {
      //if file is local, copy directly
      //note that in this case, src != dst, therefore this is a regular "cp" command, not a system replication
      //TODO: check disk space

      self->createDir(dst.substr(0, dst.rfind('/')));
      string rhome = self->reviseSysCmdPath(self->m_strHomeDir);
      string rsrc = self->reviseSysCmdPath(src);
      string rdst = self->reviseSysCmdPath(dst);
      system(("cp " + rhome + rsrc + " " + rhome + rdst).c_str());

      // if the file has been modified during the replication, remove this replica
      int type = (src == dst) ? +FileChangeType::FILE_UPDATE_REPLICA : +FileChangeType::FILE_UPDATE_NEW;

      struct stat64 s;
      if (stat64((self->m_strHomeDir + dst).c_str(), &s) < 0)
         type = +FileChangeType::FILE_UPDATE_NO;

      if (self->report(master_ip, master_port, transid, dst, type) < 0)
         system(("rm " + rhome + rdst).c_str());

      // clear this transaction
      self->m_TransManager.updateSlave(transid, self->m_iSlaveID);

      return NULL;
   }

   bool success = true;

   queue<string> tr;
   tr.push(src);

   while (!tr.empty())
   {
      string src_path = tr.front();
      tr.pop();

      // try list this path
      SectorMsg msg;
      msg.setType(101);
      msg.setKey(0);
      msg.setData(0, src_path.c_str(), src_path.length() + 1);

      Address addr;
      self->m_Routing.lookup(src_path, addr);

      if (self->m_GMP.rpc(addr.m_strIP.c_str(), addr.m_iPort, &msg, &msg) < 0)
      {
         success = false;
         break;
      }

      if (msg.getType() >= 0)
      {
         // if this is a directory, put all files and sub-drectories into the queue of files to be copied

         string filelist = msg.getData();
         unsigned int s = 0;
         while (s < filelist.length())
         {
            int t = filelist.find(';', s);
            SNode sn;
            sn.deserialize(filelist.substr(s, t - s).c_str());
            tr.push(src_path + "/" + sn.m_strName);
            s = t + 1;
         }

         continue;
      }

      // open the file and copy it to local
      msg.setType(110);
      msg.setKey(0);

      int32_t mode = SF_MODE::READ;
      msg.setData(0, (char*)&mode, 4);
      int64_t reserve = 0;
      msg.setData(4, (char*)&reserve, 8);
      int32_t localport = self->m_DataChn.getPort();
      msg.setData(12, (char*)&localport, 4);
      msg.setData(16, "\0", 1);
      msg.setData(80, src_path.c_str(), src_path.length() + 1);

      if ((self->m_GMP.rpc(addr.m_strIP.c_str(), addr.m_iPort, &msg, &msg) < 0) || (msg.getType() < 0))
      {
         success = false;
         break;
      }

      int32_t session = *(int32_t*)msg.getData();
      int64_t size = *(int64_t*)(msg.getData() + 4);
      time_t ts = *(int64_t*)(msg.getData() + 12);

      string ip = msg.getData() + 24;
      int32_t port = *(int32_t*)(msg.getData() + 64 + 24);

      if (!self->m_DataChn.isConnected(ip, port))
      {
         if (self->m_DataChn.connect(ip, port) < 0)
         {
            success = false;
            break;
         }
      }

      // download command: 3
      int32_t cmd = 3;
      self->m_DataChn.send(ip, port, session, (char*)&cmd, 4);

      int64_t offset = 0;
      self->m_DataChn.send(ip, port, session, (char*)&offset, 8);

      int response = -1;
      if ((self->m_DataChn.recv4(ip, port, session, response) < 0) || (-1 == response))
      {
         success = false;
         break;
      }

      string dst_path = dst;
      if (src != src_path)
         dst_path += "/" + src_path.substr(src.length() + 1, src_path.length() - src.length() - 1);

      //copy to .tmp first, then move to real location
      self->createDir(string(".tmp") + dst_path.substr(0, dst_path.rfind('/')));

      fstream ofs;
      ofs.open((self->m_strHomeDir + ".tmp" + dst_path).c_str(), ios::out | ios::binary | ios::trunc);

      int64_t unit = 64000000; //send 64MB each time
      int64_t torecv = size;
      int64_t recd = 0;
      while (torecv > 0)
      {
         int64_t block = (torecv < unit) ? torecv : unit;
         if (self->m_DataChn.recvfile(ip, port, session, ofs, offset + recd, block) < 0)
         {
            success = false;
            break;
         }

         recd += block;
         torecv -= block;
      }

      ofs.close();

      // update total received data size
      self->m_SlaveStat.updateIO(ip, size, +SlaveStat::SYS_IN);

      cmd = 5;
      self->m_DataChn.send(ip, port, session, (char*)&cmd, 4);
      self->m_DataChn.recv4(ip, port, session, cmd);

      if (src == dst)
      {
         //utime: update timestamp according to the original copy, for replica only; files created by "cp" have new timestamp
         utimbuf ut;
         ut.actime = ts;
         ut.modtime = ts;
         utime((self->m_strHomeDir + ".tmp" + dst_path).c_str(), &ut);
      }
   }

   string rhome = self->reviseSysCmdPath(self->m_strHomeDir);
   string rfile = self->reviseSysCmdPath(dst);
   if (success)
   {
      // move from temporary dir to the real dir when the copy is completed
      self->createDir(dst.substr(0, dst.rfind('/')));
      system(("mv " + rhome + ".tmp" + rfile + " " + rhome + rfile).c_str());

      // if the file has been modified during the replication, remove this replica
      int32_t type = (src == dst) ? +FileChangeType::FILE_UPDATE_REPLICA : +FileChangeType::FILE_UPDATE_NEW;
      if (self->report(master_ip, master_port, transid, dst, type) < 0)
         unlink((rhome + rfile).c_str());
   }
   else
   {
      // failed, remove all temporary files
      system(("rm -rf " + rhome + ".tmp" + rfile).c_str());

      self->report(master_ip, master_port, transid, "", +FileChangeType::FILE_UPDATE_NO);
   }

   // clear this transaction
   self->m_TransManager.updateSlave(transid, self->m_iSlaveID);

   return NULL;
}
示例#5
0
int Index::deserialize(ifstream& ifs, map<string, SNode>& metadata, const Address* addr)
{
   vector<string> dirs;
   dirs.resize(1024);
   map<string, SNode>* currdir = &metadata;
   int currlevel = 1;

   while (!ifs.eof())
   {
      char tmp[4096];
      tmp[4095] = 0;
      char* buf = tmp;

      ifs.getline(buf, 4096);
      int len = strlen(buf);
      if ((len <= 0) || (len >= 4095))
         continue;

      for (int i = 0; i < len; ++ i)
      {
         if (buf[i] == ' ')
         {
            buf[i] = '\0';
            break;
         }
      }

      int level = atoi(buf);

      SNode sn;
      sn.deserialize(buf + strlen(buf) + 1);
      if ((!sn.m_bIsDir) && (NULL != addr))
      {
         sn.m_sLocation.clear();
         sn.m_sLocation.insert(*addr);
      }

      if (level == currlevel)
      {
         (*currdir)[sn.m_strName] = sn;
         dirs[level] = sn.m_strName;
      }
      else if (level == currlevel + 1)
      {
         map<string, SNode>::iterator s = currdir->find(dirs[currlevel]);
         currdir = &(s->second.m_mDirectory);
         currlevel = level;

         (*currdir)[sn.m_strName] = sn;
         dirs[level] = sn.m_strName;
      }
      else if (level < currlevel)
      {
         currdir = &metadata;

         for (int i = 1; i < level; ++ i)
         {
            map<string, SNode>::iterator s = currdir->find(dirs[i]);
            currdir = &(s->second.m_mDirectory);
         }
         currlevel = level;

         (*currdir)[sn.m_strName] = sn;
         dirs[level] = sn.m_strName;
      }
   }

   return 0;
}
示例#6
0
int Index::update(const string& fileinfo, const Address& loc, const int& type)
{
   CMutexGuard mg(m_MetaLock);

   SNode sn;
   sn.deserialize(fileinfo.c_str());
   sn.m_sLocation.insert(loc);

   vector<string> dir;
   parsePath(sn.m_strName.c_str(), dir);

   if (dir.empty())
      return -1;

   string filename = *(dir.rbegin());
   sn.m_strName = filename;
   dir.erase(dir.begin() + dir.size() - 1);

   map<string, SNode>* currdir = &m_mDirectory;
   map<string, SNode>::iterator s;
   for (vector<string>::iterator d = dir.begin(); d != dir.end(); ++ d)
   {
      s = currdir->find(*d);
      if (s == currdir->end())
      {
         if ((type == 3) || (type == 2))
         {
            // this is for new files only
            return -1;
         }

         SNode n;
         n.m_strName = *d;
         n.m_bIsDir = true;
         n.m_llTimeStamp = sn.m_llTimeStamp;
         n.m_llSize = 0;
         (*currdir)[*d] = n;
         s = currdir->find(*d);
      }

      s->second.m_llTimeStamp = sn.m_llTimeStamp;

      currdir = &(s->second.m_mDirectory);
   }

   s = currdir->find(filename);
   if (s == currdir->end())
   {
      if ((type == 3) || (type == 2))
      {
         // this is for new files only
         return -1;
      }

      (*currdir)[filename] = sn;
      return 1;
   }
   else
   {
      if ((type == 1) || (type == 2))
      {
         // modification to an existing copy
         // this maybe a new file and the master already registered the file when it is created, so it is treated as an existing file too
	 if ((s->second.m_llSize != sn.m_llSize) || (s->second.m_llTimeStamp != sn.m_llTimeStamp))
         {
            s->second.m_llSize = sn.m_llSize;
            s->second.m_llTimeStamp = sn.m_llTimeStamp;
            s->second.m_sLocation.insert(loc);
         }

         return s->second.m_sLocation.size();
      }

      if (type == 3)
      {
         // a new replica
         if (s->second.m_sLocation.find(loc) != s->second.m_sLocation.end())
            return -1;

         if ((s->second.m_llSize != sn.m_llSize) || (s->second.m_llTimeStamp != sn.m_llTimeStamp))
            return -1;

         s->second.m_sLocation.insert(loc);
         return s->second.m_sLocation.size();
      }
   }

   return -1;
}