382 lines
9.9 KiB
C++
382 lines
9.9 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
|
|
----
|
|
|
|
|
|
//[$][\$]
|
|
|
|
*/
|
|
#ifndef REMOTEMETADATA_H
|
|
#define REMOTEMETADATA_H
|
|
|
|
#include "str.h"
|
|
#include "uri.h"
|
|
#include "../dfs/dfs.h"
|
|
#include "numberUtils.h"
|
|
|
|
namespace dfs {
|
|
|
|
struct ChunkLocation : SerializeAble {
|
|
|
|
dfs::URI dataNodeUri;
|
|
|
|
Str chunkId;
|
|
|
|
/**
|
|
* indicates whether this locations is broken
|
|
* just runtimeInfo will not be persistet
|
|
*/
|
|
bool broken;
|
|
|
|
ChunkLocation() {
|
|
broken=false;
|
|
}
|
|
|
|
static ChunkLocation deserialize(StrReader &r) {
|
|
ChunkLocation location;
|
|
location.dataNodeUri = dfs::URI::fromString(r.readStrSer());
|
|
location.chunkId = r.readStrSer();
|
|
return location;
|
|
}
|
|
|
|
virtual void serializeTo(ToStrSerializer &serializer) const {
|
|
serializer.append(dataNodeUri.toString());
|
|
serializer.append(chunkId);
|
|
}
|
|
|
|
};
|
|
|
|
class ChunkInfo : SerializeAble {
|
|
|
|
public:
|
|
|
|
NUMBER offsetInFile;
|
|
NUMBER length;
|
|
NUMBER order;
|
|
|
|
ChunkLocation *chunkLocationList;
|
|
|
|
int chunkLocationListLength;
|
|
|
|
ChunkInfo() {
|
|
chunkLocationListLength = 0;
|
|
chunkLocationList = 0;
|
|
}
|
|
|
|
ChunkInfo(const ChunkInfo &other) {
|
|
offsetInFile = other.offsetInFile;
|
|
length = other.length;
|
|
order = other.order;
|
|
|
|
chunkLocationListLength = other.chunkLocationListLength;
|
|
chunkLocationList = 0;
|
|
if (other.chunkLocationList != 0) {
|
|
chunkLocationList = new ChunkLocation[chunkLocationListLength];
|
|
for (int i = 0; i < chunkLocationListLength; i++) {
|
|
chunkLocationList[i] = other.chunkLocationList[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
ChunkInfo &operator=(const ChunkInfo &other) {
|
|
if (this != &other) {
|
|
delete[] chunkLocationList;
|
|
length = other.length;
|
|
order = other.order;
|
|
offsetInFile = other.offsetInFile;
|
|
chunkLocationListLength = other.chunkLocationListLength;
|
|
chunkLocationList = 0;
|
|
if (other.chunkLocationListLength > 0) {
|
|
chunkLocationList = new ChunkLocation[chunkLocationListLength];
|
|
for (int i = 0; i < chunkLocationListLength; i++)
|
|
chunkLocationList[i] = other.chunkLocationList[i];
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
~ChunkInfo() {
|
|
delete[] chunkLocationList;
|
|
chunkLocationList = 0;
|
|
}
|
|
|
|
void allocateLocations(int locationCount) {
|
|
delete[] chunkLocationList;
|
|
chunkLocationList = new ChunkLocation[locationCount];
|
|
chunkLocationListLength = locationCount;
|
|
}
|
|
|
|
/**
|
|
* finds location by uri
|
|
* @param uri
|
|
* @return
|
|
*/
|
|
ChunkLocation* findLocationByURI(const Str& uri) {
|
|
for (int i=0;i<chunkLocationListLength;i++) {
|
|
if (chunkLocationList[i].dataNodeUri.toString() == uri) {
|
|
return chunkLocationList+i;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* marks locations as broken by using the state of other chunk info
|
|
* @param pOther
|
|
*/
|
|
void markDataNodeAsBrokenFromOtherChunk(ChunkInfo* pOther) {
|
|
for (int l=0;l<pOther->chunkLocationListLength;l++) {
|
|
if (pOther->chunkLocationList[l].broken) {
|
|
ChunkLocation* match =
|
|
findLocationByURI(
|
|
pOther->chunkLocationList[l].dataNodeUri.toString());
|
|
if (match != 0) {
|
|
//std::cout << "NEED TO MARK "
|
|
// << match->dataNodeUri.toString() << std::endl;
|
|
match->broken=true;
|
|
markDataNodeAsBroken(match->dataNodeUri.toString());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void markDataNodeAsBroken(const Str &uri) {
|
|
|
|
int foundCount = 0;
|
|
for (int i = 0; i < chunkLocationListLength; i++) {
|
|
if ((chunkLocationList + i)->dataNodeUri.toString() == uri) {
|
|
foundCount++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (foundCount == 0) return;
|
|
|
|
int newLocLength = chunkLocationListLength - foundCount;
|
|
|
|
if (newLocLength == 0) {
|
|
delete[] chunkLocationList;
|
|
chunkLocationList = 0;
|
|
chunkLocationListLength = 0;
|
|
} else {
|
|
ChunkLocation *newList = new ChunkLocation[newLocLength];
|
|
int targetIndex = 0;
|
|
for (int i = 0; i < chunkLocationListLength; i++) {
|
|
if ((chunkLocationList + i)->dataNodeUri.toString() == uri) {
|
|
} else {
|
|
newList[targetIndex++] = chunkLocationList[i];
|
|
}
|
|
}
|
|
delete[] chunkLocationList;
|
|
chunkLocationList = newList;
|
|
chunkLocationListLength = newLocLength;
|
|
}
|
|
|
|
}
|
|
|
|
virtual void serializeTo(ToStrSerializer &serializer) const {
|
|
serializer.appendDefaultUnsigned(order);
|
|
serializer.appendDefaultUnsigned(offsetInFile);
|
|
serializer.appendDefaultUnsigned(length);
|
|
serializer.appendDefaultUnsignedShort(chunkLocationListLength);
|
|
for (int i = 0; i < chunkLocationListLength; i++) {
|
|
ChunkLocation *pl = &chunkLocationList[i];
|
|
pl->serializeTo(serializer);
|
|
}
|
|
}
|
|
|
|
static ChunkInfo deserialize(StrReader &r) {
|
|
ChunkInfo i;
|
|
i.order = r.readLong(12);
|
|
i.offsetInFile = r.readLong(12);
|
|
i.length = r.readLong(12);
|
|
i.allocateLocations(r.readInt(5));
|
|
for (int j = 0; j < i.chunkLocationListLength; j++) {
|
|
i.chunkLocationList[j] = ChunkLocation::deserialize(r);
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
};
|
|
|
|
class IndexEntry : SerializeAble {
|
|
public:
|
|
|
|
static IndexEntry
|
|
create(const Str &fileId, int chunkInfoCount, const Str &category) {
|
|
IndexEntry e;
|
|
e.fileId = fileId;
|
|
e.chunkInfoList = new ChunkInfo[chunkInfoCount];
|
|
e.chunkInfoListLength = chunkInfoCount;
|
|
e.category = category;
|
|
return e;
|
|
}
|
|
|
|
static IndexEntry
|
|
createForOneChunkFile(const Str &fileId, const Str &category) {
|
|
return create(fileId, 1, category);
|
|
}
|
|
|
|
|
|
/**
|
|
* optional category of index entry
|
|
*/
|
|
Str category;
|
|
|
|
|
|
/**
|
|
* the fileid
|
|
*/
|
|
Str fileId;
|
|
|
|
/**
|
|
* a list of chunk info
|
|
*/
|
|
ChunkInfo *chunkInfoList;
|
|
|
|
/**
|
|
* the length of chunkInfo
|
|
*/
|
|
int chunkInfoListLength;
|
|
|
|
/**
|
|
* indicates whether the file is deleted
|
|
*/
|
|
bool isDeleted;
|
|
|
|
IndexEntry() {
|
|
isDeleted = false;
|
|
chunkInfoList = 0;
|
|
chunkInfoListLength = 0;
|
|
}
|
|
|
|
IndexEntry(const IndexEntry &other) {
|
|
|
|
fileId = other.fileId;
|
|
category = other.category;
|
|
isDeleted = other.isDeleted;
|
|
|
|
this->chunkInfoListLength = other.chunkInfoListLength;
|
|
if (this->chunkInfoListLength > 0) {
|
|
this->chunkInfoList = new ChunkInfo[this->chunkInfoListLength];
|
|
for (int i = 0; i < chunkInfoListLength; i++) {
|
|
this->chunkInfoList[i] = other.chunkInfoList[i];
|
|
}
|
|
} else {
|
|
this->chunkInfoList = 0;
|
|
}
|
|
}
|
|
|
|
void markDataNodeAsBroken(const Str &uri) {
|
|
for (int i = 0; i < chunkInfoListLength; i++) {
|
|
(this->chunkInfoList + i)->markDataNodeAsBroken(uri);
|
|
}
|
|
}
|
|
|
|
int reallocateForAdditionalChunkInfo(int amountToAdd) {
|
|
ChunkInfo *newList = new ChunkInfo[chunkInfoListLength + amountToAdd];
|
|
for (int i = 0; i < chunkInfoListLength; i++) {
|
|
newList[i] = chunkInfoList[i];
|
|
}
|
|
delete[] chunkInfoList;
|
|
int startingIndex = chunkInfoListLength;
|
|
chunkInfoList = newList;
|
|
chunkInfoListLength += amountToAdd;
|
|
return startingIndex;
|
|
}
|
|
|
|
ChunkInfo *lastChunk() {
|
|
return chunkInfoListLength == 0 ? 0 : &chunkInfoList[chunkInfoListLength -
|
|
1];
|
|
}
|
|
|
|
IndexEntry &operator=(const IndexEntry &other) {
|
|
if (this != &other) {
|
|
|
|
fileId = other.fileId;
|
|
category = other.category;
|
|
isDeleted = other.isDeleted;
|
|
chunkInfoListLength = other.chunkInfoListLength;
|
|
|
|
delete[] chunkInfoList;
|
|
chunkInfoList = 0;
|
|
if (chunkInfoListLength > 0) {
|
|
chunkInfoList = new ChunkInfo[chunkInfoListLength];
|
|
for (int i = 0; i < chunkInfoListLength; i++)
|
|
chunkInfoList[i] = other.chunkInfoList[i];
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
~IndexEntry() {
|
|
delete[] chunkInfoList;
|
|
chunkInfoList = 0;
|
|
}
|
|
|
|
bool isSinglePartFile() {
|
|
return chunkInfoListLength == 1;
|
|
}
|
|
|
|
unsigned long long calculateFileSize() const {
|
|
unsigned long long fileSize = 0;
|
|
for (int i = 0; i < chunkInfoListLength; i++) {
|
|
fileSize += chunkInfoList[i].length;
|
|
}
|
|
return fileSize;
|
|
}
|
|
|
|
void serializeTo(ToStrSerializer &ser) const {
|
|
|
|
ser.append(fileId);
|
|
ser.append(chunkInfoListLength, 4);
|
|
ser.append(category);
|
|
|
|
for (int iChunkInfoIndex = 0;
|
|
iChunkInfoIndex < chunkInfoListLength; iChunkInfoIndex++) {
|
|
ChunkInfo *pci = &chunkInfoList[iChunkInfoIndex];
|
|
pci->serializeTo(ser);
|
|
}
|
|
}
|
|
|
|
static IndexEntry deserialize(const Str &s) {
|
|
StrReader r(&s);
|
|
|
|
Str fileId = r.readStrSer();
|
|
int infoLength = r.readInt(4);
|
|
Str category = r.readStrSer();
|
|
|
|
IndexEntry e = IndexEntry::create(fileId, infoLength, category);
|
|
for (int i = 0; i < infoLength; i++) {
|
|
e.chunkInfoList[i] = ChunkInfo::deserialize(r);
|
|
}
|
|
|
|
return e;
|
|
}
|
|
|
|
|
|
};
|
|
};
|
|
#endif
|