Files
secondo/Tools/DFS/dfs/remotedfs_store.cpp
2026-01-23 17:03:45 +08:00

415 lines
12 KiB
C++

/*
----
This file is part of SECONDO.
Realizing a simple distributed filesystem for master thesis of stephan scheide
Copyright (C) 2015,
Faculty of Mathematics and Computer Science,
Database Systems for New Applications.
SECONDO is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
SECONDO is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
//[$][\$]
*/
#include "remotedfs.h"
#include "../commlayer/EndpointClient.h"
#include "../shared/io.h"
#include "../shared/remotemetadata.h"
#include "../shared/numberUtils.h"
#include <iostream>
using namespace dfs::remote;
using namespace dfs::comm;
using namespace dfs;
using namespace std;
void RemoteFilesystem::appendToFile(FILEID fileId, FILEBUFFER appendix,
long length) {
if (!this->hasFile(fileId)) {
this->storeFullBufferFromMemory(fileId, appendix, length);
return;
}
this->appendToExistingFile(fileId, appendix, length);
}
void RemoteFilesystem::appendToExistingFile(FILEID fileId, FILEBUFFER appendix,
long length) {
bool canDebug = this->logger->canDebug;
//we send appd<file><length> to index
//we will get the info where to send content
ToStrSerializer ser;
ser.appendRaw("appd");
ser.append(fileId);
ser.appendUInt64(length);
Str r = syncm(ser.output);
assertResponse(r);
StrReader reader(&r);
reader.setPos(4);
UI64 count = reader.readUInt64();
for (UI64 i = 0; i < count; i++) {
Str verb = reader.readStrSer();
if (canDebug) debug(Str("got verb ").append(verb));
if (verb == "donewchunk") {
Str uri = reader.readStrSer();
UI64 bufferOffset = reader.readUInt64();
UI64 bufferLengthToSend = reader.readUInt64();
UI64 order = reader.readUInt64();
Str category = reader.readStrSer();
//build command for datanode
ToStrSerializer cmd;
cmd.appendRaw("part");
if (category.len() > 0) {
cmd.append(category.len(), 3);
cmd.appendRaw(category);
} else {
cmd.appendRaw("000");
}
cmd.appendUInt64(bufferLengthToSend);
cmd.appendRaw(Str(appendix + bufferOffset, bufferLengthToSend));
//send command to data node
URI uriDataNode = URI::fromString(uri);
Str response;
if (sendRequestToDataNodeKilling(uriDataNode, cmd.output, &response)) {
//Str response = syncmg(uriDataNode,cmd.output);
assertResponse(response);
//result is new chunk name
StrReader readerDataNode(&response);
readerDataNode.setPos(4);
Str localChunkId = readerDataNode.readStrSer();
this->registerLocalChunkIdToIndex(fileId, uriDataNode, order,
localChunkId);
}
} else if (verb == "doappendtochunk") {
Str uri = reader.readStrSer();
Str chunkId = reader.readStrSer();
UI64 bufferOffset = reader.readUInt64();
UI64 bufferLengthToSend = reader.readUInt64();
UI64 newTotalSize = reader.readUInt64();
UI64 newChunkSize = reader.readUInt64();
URI uriDataNode = URI::fromString(uri);
ToStrSerializer serDataNode;
serDataNode.appendRaw("appc");
serDataNode.append(chunkId);
serDataNode.appendUInt64(newChunkSize);
serDataNode.append(Str(appendix, length));
Str response;
//Str response = syncmg(uriDataNode,serDataNode.output);
if (sendRequestToDataNodeKilling(uriDataNode, serDataNode.output,
&response)) {
assertResponse(response);
}
}
}
this->triggerIndexBackup();
}
void RemoteFilesystem::storeFile(FILEID fileId, FILEBUFFER content, long length,
CATEGORY c) {
storeFullBufferFromMemory(fileId, content, length, c);
}
Str getRequestForStorageNewFile(FILEID fileId, long contentLength,
CATEGORY category) {
ToStrSerializer serIndex;
serIndex.appendRaw("stor");
serIndex.appendUInt64(contentLength);
//serIndex.append(contentLength,12);
serIndex.append(Str(fileId));
if (category != 0) {
serIndex.append(Str(category));
} else {
serIndex.appendEmptyStr();
}
return serIndex.output;
}
void
RemoteFilesystem::storeFullBufferFromMemory(FILEID fileId, FILEBUFFER content,
long contentLength,
CATEGORY category) {
//delete existing file
this->deleteFile(fileId);
debug("storeFileFromLocal begin");
Str msg = getRequestForStorageNewFile(fileId, contentLength, category);
debug("storeFileFromLocal send storage request message to index");
Str r = syncm(msg);
debug(Str("storeFileFromLocal - result from index node - ").append(r));
assertResponse(r);
IndexEntry indexEntry = IndexEntry::deserialize(r.substr(4));
debug(Str("storeFileFromLocal - fileid ").append(indexEntry.fileId));
int pic = indexEntry.chunkInfoListLength;
debug(Str("Anzahl Teile - ").append(pic));
for (int p = 0; p < pic; p++) {
ChunkInfo *pci = &indexEntry.chunkInfoList[p];
long order = pci->order;
long offset = pci->offsetInFile;
long length = pci->length;
debug(Str("order, offsetInFile, length").append(order).append(
" ").append(offset).append(" ").append(length));
int locationListLength = pci->chunkLocationListLength;
for (int d = 0; d < locationListLength; d++) {
ChunkLocation *pcl = &pci->chunkLocationList[d];
URI uri = pcl->dataNodeUri;
debug((Str("save partnumber ").append(order).append(
"with size ").append(length).append(" at URL ").append(
uri.toString())));
//cmd for datanode
//part<length:ui64><lcat:3stellig>
ToStrSerializer serIndex;
serIndex.appendRaw("part");
if (category != 0) {
serIndex.append(strlen(category), 3);
serIndex.appendRaw(category);
} else {
serIndex.appendRaw("000");
}
//Wir schicken den (Teilinhalt) der Datei an alle Datenknoten
char *partialContent = new char[length];
memcpy(partialContent, (void *) (content + offset), length);
serIndex.appendUInt64(length);
serIndex.appendRaw(Str(partialContent, length));
//Str result = syncmg(uri,serIndex.output);
Str result;
if (this->sendRequestToDataNodeKilling(uri, serIndex.output, &result)) {
delete[] partialContent;
assertResponse(result);
//wir haben eine Chunk-Kennung erhalten
StrReader readerStore(&result);
readerStore.setPos(4);
Str chunk = readerStore.readStrSer();
debug(Str("got chunk is ").append(chunk));
//chunk dem master bekannt machen
//chun(fileId,chunkId,dataNodeUri,order)
this->registerLocalChunkIdToIndex(indexEntry.fileId, uri, order, chunk);
}
}
}
this->triggerIndexBackup();
}
void
RemoteFilesystem::registerLocalChunkIdToIndex(const Str &fileId, const URI &uri,
long order,
const Str &localChunkId) {
ToStrSerializer ser;
ser.appendRaw("chun");
ser.append(fileId);
ser.append(localChunkId);
ser.append(uri.toString());
ser.appendDefaultUnsigned(order);
syncm(ser.output);
}
void RemoteFilesystem::storeFileFromLocal(FILEID fileId, FILEPATH localPath,
CATEGORY category) {
this->deleteFile(fileId);
long contentLength = io::file::fileSize(localPath);
int bufsize = this->fileCopyBuffer;
int amountRead = 0;
FILE *fp = fopen(localPath, "rb");
char *fileReadBuffer = new char[bufsize];
// reserve indexentry on index server
Str msg = getRequestForStorageNewFile(fileId, contentLength, category);
Str r = syncm(msg);
IndexEntry indexEntry = IndexEntry::deserialize(r.substr(4));
int pic = indexEntry.chunkInfoListLength;
if (canDebug) {
debug("got index entry from index node");
debug(Str("amount of chunk info ").append(pic));
}
for (int p = 0; p < pic; p++) {
ChunkInfo *pci = &indexEntry.chunkInfoList[p];
long order = pci->order;
long offset = pci->offsetInFile;
long length = pci->length;
if (canDebug) {
debug(Str("chunk ").append(p));
debug(Str("\torder ").append(order));
debug(Str("\toffset ").append(offset));
debug(Str("\tlength ").append(length));
}
int locationListLength = pci->chunkLocationListLength;
if (canDebug)
debug(Str("\tamount of locations ").append(locationListLength));
for (int d = 0; d < locationListLength; d++) {
ChunkLocation *pcl = &pci->chunkLocationList[d];
URI uri = pcl->dataNodeUri;
bool firstDataToThisLocation = true;
bool useThisLocation = false;
// create a new chunk at data node
Str chunkId;
if (firstDataToThisLocation) {
firstDataToThisLocation = false;
ToStrSerializer ser;
ser.appendRaw("parr");
if (category != 0) {
ser.append(strlen(category), 3);
ser.appendRaw(category);
} else {
ser.appendRaw("000");
}
ser.appendUInt64(length);
Str result;
if (this->sendRequestToDataNodeKilling(uri, ser.output, &result)) {
assertResponse(result);
StrReader readerStore(&result);
readerStore.setPos(4);
chunkId = readerStore.readStrSer();
if (canDebug) debug(Str("got new chunk ").append(chunkId));
this->registerLocalChunkIdToIndex(indexEntry.fileId, uri, order,
chunkId);
if (canDebug) debug("registered to index done");
useThisLocation = true;
}
}
//read content from file and put it as data to the data nodes chunk
if (useThisLocation) {
if (canDebug) debug("use this location");
fseek(fp, pci->offsetInFile, SEEK_SET);
UI64 bytesAlreadyTransfered = 0;
UI64 bytesToBeTransfered = 0;
UI64 bufSizeToUse = bufsize;
UI64 bytesLeft = length;
if (bufSizeToUse > length) bufSizeToUse = length;
while ((amountRead = fread(fileReadBuffer, 1, bufSizeToUse, fp)) > 0) {
bytesToBeTransfered += amountRead;
bytesLeft -= amountRead;
if (bytesLeft < bufSizeToUse) bufSizeToUse = bytesLeft;
if (canDebug) {
debug("");
debug("read bytes from local file");
debug(Str("amountRead ").append(amountRead));
debug(Str("bytesToBeTransfered ").append(bytesToBeTransfered));
debug(Str("bytesLeft ").append(bytesLeft));
}
UI64 bytesToSend = amountRead;
if (bytesToBeTransfered > length) {
bytesToSend = bytesToBeTransfered - length;
}
if (canDebug) {
debug(Str("bytesToSend ").append(bytesToSend));
}
ToStrSerializer ser;
ser.appendRaw("@00000000000000");
ser.appendRaw("parc");
ser.append(chunkId);
ser.appendUInt64(bytesToSend);
//alte, langsame loesung
//ser.append(Str(fileReadBuffer, bytesToSend));
ser.appendRawBinary(bytesToSend,fileReadBuffer);
//ser.appendBinaryAsSer(bytesToSend,fileReadBuffer);
Str len = Str(ser.output.len()).prepend(14);
char* raw = ser.output.buf();
for (int xx=0;xx<14;xx++) {
raw[xx+1] = len.buf()[xx];
}
Str result;
this->sendRequestToDataNodeKilling(uri, ser.output, &result);
bytesAlreadyTransfered += bytesToSend;
if (canDebug) {
debug(Str("check if break loop ")
.append(bytesAlreadyTransfered)
.append(" ").append(length));
}
if (bytesAlreadyTransfered >= length) break;
}
}
}
}
fclose(fp);
delete[] fileReadBuffer;
this->triggerIndexBackup();
}
void
RemoteFilesystem::appendToFileFromLocalFile(FILEID fileId, FILEPATH localPath) {
long filesize = io::file::fileSize(localPath);
char *content = io::file::getFileContent(localPath);
appendToFile(fileId, content, filesize);
}