486 lines
15 KiB
C++
486 lines
15 KiB
C++
/*
|
|
* =====================================================================================
|
|
*
|
|
* Filename: dataset.h
|
|
*
|
|
* Description:
|
|
*
|
|
* Version: 1.0
|
|
* Created: 04/24/2007 10:25:35 AM EDT
|
|
* Revision: none
|
|
* Compiler: gcc
|
|
*
|
|
* Author: Nikolaos Vasiloglou (NV), nvasil@ieee.org
|
|
* Company: Georgia Tech Fastlab-ESP Lab
|
|
*
|
|
* =====================================================================================
|
|
*/
|
|
#ifndef BINARY_DATASET_
|
|
#define BINARY_DATASET_
|
|
#include <sys/unistd.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <string>
|
|
#include "fastlib/fastlib.h"
|
|
#include "u/nvasil/loki/NullType.h"
|
|
#include "u/nvasil/tree/point.h"
|
|
// BinaryDataset
|
|
// Use this class to read a binary data file that is also
|
|
// accompanied by a file with the index values (uint64)
|
|
// It is templetized so that you can use it with different precisions
|
|
// for data
|
|
using namespace std;
|
|
template <typename PRECISION>
|
|
class BinaryDataset {
|
|
FORBID_COPY(BinaryDataset<PRECISION>);
|
|
template<typename > friend class BinaryDatasetTest;
|
|
public:
|
|
typedef PRECISION Precision_t;
|
|
static const int32 kMinimumPagesToAdvise=10;
|
|
friend class Iterator;
|
|
class Iterator {
|
|
public:
|
|
typedef random_access_iterator_tag iterator_category;
|
|
typedef CompletePoint<Precision_t> value_type;
|
|
typedef index_t difference_type;
|
|
typedef CompletePoint<Precision_t>* pointer;
|
|
typedef CompletePoint<Precision_t>& reference;
|
|
Iterator(){
|
|
}
|
|
Iterator(BinaryDataset<Precision_t> *dataset) {
|
|
set_=dataset;
|
|
current_pos_=0;
|
|
}
|
|
Iterator &operator=(const Iterator &other) {
|
|
this->set_=other.set_;
|
|
this->current_pos_=other.current_pos_;
|
|
return *this;
|
|
}
|
|
Iterator operator++() {
|
|
current_pos_++;
|
|
DEBUG_ASSERT_MSG(current_pos_>(signed long long)set_->get_num_of_points(),
|
|
"Iterator out of bounds %lli>%lli",
|
|
(signed long long)current_pos_,
|
|
(signed long long)set_->get_num_of_points());
|
|
}
|
|
Iterator operator+(index_t i) {
|
|
Iterator it(*this);
|
|
it.current_pos_+=i;
|
|
DEBUG_ASSERT_MSG(it.current_pos_<(signed long long)set_->get_num_of_points()
|
|
&& it.current_pos_>=0,
|
|
"iterator out of bounds %lli>=%lli\n",
|
|
(signed long long)it.current_pos_,
|
|
(signed long long)set_->get_num_of_points());
|
|
return it;
|
|
}
|
|
Iterator operator+(const Iterator &other) {
|
|
Iterator it(*this);
|
|
it.current_pos_+=other.current_pos_;
|
|
DEBUG_ASSERT_MSG(it.current_pos_<(signed long long)set_->get_num_of_points()
|
|
&& it.current_pos_>=0,
|
|
"iterator out of bounds %lli>=%lli\n",
|
|
(signed long long)it.current_pos_,
|
|
(signed long long)set_->get_num_of_points());
|
|
return it;
|
|
|
|
}
|
|
Iterator operator--() {
|
|
current_pos_--;
|
|
DEBUG_ASSERT_MSG(current_pos_<0,
|
|
"Iterator out of bounds %lli <0",
|
|
(signed long long)current_pos_ );
|
|
|
|
}
|
|
Iterator operator-(index_t i) {
|
|
Iterator it(*this);
|
|
it.current_pos_-=i;
|
|
DEBUG_ASSERT_MSG(it.current_pos_<(signed long long)set_->get_num_of_points()
|
|
&& it.current_pos_>=0,
|
|
"iterator out of bounds %lli>=%lli\n",
|
|
(unsigned long long)it.current_pos_,
|
|
(unsigned long long)set_->get_num_of_points());
|
|
return it;
|
|
|
|
}
|
|
index_t operator-(const Iterator &other) {
|
|
index_t diff = current_pos_-other.current_pos_;
|
|
DEBUG_ASSERT_MSG(current_pos_<(signed long long)set_->get_num_of_points()
|
|
&& current_pos_>=0,
|
|
"iterator out of bounds %lli>=%lli\n",
|
|
(unsigned long long)current_pos_,
|
|
(unsigned long long)set_->get_num_of_points());
|
|
return diff;
|
|
|
|
}
|
|
Iterator operator/(const int divider) {
|
|
Iterator it(*this);
|
|
it.current_pos_/=divider;
|
|
return it;
|
|
}
|
|
bool operator==(const Iterator &other) {
|
|
if (likely(other.set_==set_)) {
|
|
return current_pos_==other.current_pos_;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
bool operator!=(const Iterator &other) {
|
|
if (likely(other.set_==set_)) {
|
|
return current_pos_!=other.current_pos_;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
bool operator<=(const Iterator &other) {
|
|
if (likely(other.set_==set_)) {
|
|
return current_pos_<=other.current_pos_;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
bool operator>(const Iterator &other) {
|
|
if (likely(other.set_==set_)) {
|
|
return current_pos_>other.current_pos_;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
bool operator<(const Iterator &other) {
|
|
if (likely(other.set_==set_)) {
|
|
return current_pos_<other.current_pos_;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
CompletePoint<Precision_t> &operator*() {
|
|
CompletePoint<Precision_t> point;
|
|
point.Alias(set_->At(current_pos_),
|
|
set_->get_id(current_pos_),
|
|
set_->get_dimension());
|
|
return point;
|
|
}
|
|
CompletePoint<Precision_t> &operator->() {
|
|
CompletePoint<Precision_t> point;
|
|
point.Alias(set_->At(current_pos_),
|
|
set_->get_id(current_pos_),
|
|
set_->get_dimension());
|
|
return point;
|
|
}
|
|
private:
|
|
BinaryDataset<Precision_t> *set_;
|
|
index_t current_pos_;
|
|
};
|
|
BinaryDataset() {
|
|
data_file_="";
|
|
index_file_="";
|
|
data_=NULL;
|
|
index_=NULL;
|
|
page_size_ = getpagesize();
|
|
}
|
|
~BinaryDataset() {
|
|
}
|
|
// Initializes a the BinaryDataset from two existent files
|
|
// one for data and one for the index
|
|
success_t Init(string data_file, string index_file) {
|
|
data_file_=data_file;
|
|
index_file_=index_file;
|
|
ReadDimNumOfPointsFromFile(data_file_);
|
|
data_=(Precision_t*)MemoryMap(data_file_, sizeof(int32));
|
|
index_=(uint64*)MemoryMap(index_file_,0);
|
|
return SUCCESS_PASS;
|
|
}
|
|
// If the index file is not given it assumes it has the same name as
|
|
// the data file appended with ind
|
|
success_t Init(string data_file) {
|
|
string temp=data_file + string(".ind");
|
|
Init(data_file, temp);
|
|
return SUCCESS_PASS;
|
|
}
|
|
// Use this to create a new BinarayDataset file, If you omit
|
|
// the index file it will create a index file appended with .ind
|
|
// extension.
|
|
success_t Init(string data_file, uint64 num_of_points,
|
|
int32 dimension) {
|
|
data_file_=data_file;
|
|
index_file_=data_file;
|
|
index_file_.append(".ind");
|
|
num_of_points_=num_of_points;
|
|
Init(data_file_, index_file_, num_of_points_, dimension);
|
|
return SUCCESS_PASS;
|
|
}
|
|
|
|
success_t Init(string data_file, string index_file,
|
|
uint64 num_of_points, int32 dimension) {
|
|
data_file_=data_file;
|
|
index_file_=index_file;
|
|
num_of_points_=num_of_points;
|
|
dimension_=dimension;
|
|
CreateDataFile(data_file, dimension, num_of_points);
|
|
CreateIndexFile(index_file, num_of_points);
|
|
data_=(Precision_t*)MemoryMap(data_file_, sizeof(int32));
|
|
index_=(uint64*)MemoryMap(index_file_,0);
|
|
return SUCCESS_PASS;
|
|
}
|
|
|
|
Iterator Begin() {
|
|
Iterator it(this);
|
|
return it;
|
|
}
|
|
|
|
Iterator End() {
|
|
Iterator it(this);
|
|
it.current_pos_=num_of_points_;
|
|
return it;
|
|
}
|
|
inline void AdviseWillNeed(index_t start, index_t end) {
|
|
index_t num_of_bytes1 = (end-start)*dimension_*sizeof(Precision_t);
|
|
index_t num_of_bytes2 = (end-start)*sizeof(index_t);
|
|
Advise1(data_, start*dimension_*sizeof(Precision_t), num_of_bytes1);
|
|
Advise2(index_, start*sizeof(index_t), num_of_bytes2);
|
|
}
|
|
inline void AdviseWillNotNeed(index_t start, index_t end) {
|
|
index_t num_of_bytes1 = (end-start)*dimension_*sizeof(Precision_t);
|
|
index_t num_of_bytes2 = (end-start)*sizeof(index_t);
|
|
Advise2(data_, start*dimension_*sizeof(Precision_t), num_of_bytes1);
|
|
Advise2(index_, start*sizeof(index_t), num_of_bytes2);
|
|
}
|
|
|
|
|
|
// Use this to swap the points of a dataset
|
|
// swaps the index values as well
|
|
inline void Swap(uint64 i, uint64 j) {
|
|
Precision_t temp[dimension_];
|
|
memcpy(temp, At(j), dimension_ * sizeof(Precision_t));
|
|
memcpy(At(j), At(i), dimension_ * sizeof(Precision_t));
|
|
memcpy(At(i), temp, dimension_ * sizeof(Precision_t));
|
|
uint64 temp_index=index_[i];
|
|
index_[i]=index_[j];
|
|
index_[j]=temp_index;
|
|
}
|
|
// Use this for destruction
|
|
void Destruct() {
|
|
MemoryUnmap(data_, data_file_, sizeof(int32));
|
|
MemoryUnmap(index_, index_file_, 0);
|
|
}
|
|
// returns a matrix on the data
|
|
inline Matrix get_data_matrix() {
|
|
Matrix matrix;
|
|
matrix.Alias(data_, num_of_points_/dimension_, dimension_);
|
|
return matrix;
|
|
}
|
|
// returns a vector on the index
|
|
/*inline Vector get_index_vector() {
|
|
Vector vector;
|
|
vector.Alias(index_, num_of_points_);
|
|
return vector;
|
|
}*/
|
|
inline Point<Precision_t, Loki::NullType> get_point(index_t i) {
|
|
Point<Precision_t, Loki::NullType> point;
|
|
point.Alias(At(i), get_id(i));
|
|
return point;
|
|
}
|
|
// returns a pointer on the data at the ith point
|
|
inline Precision_t* At(uint64 i) {
|
|
DEBUG_ASSERT_MSG(i<num_of_points_,
|
|
"Attempt to acces data out of range %llu>%llu",
|
|
(unsigned long long)i,
|
|
(unsigned long long)num_of_points_);
|
|
return data_+i*dimension_;
|
|
}
|
|
// returns a reference on the i,j element
|
|
inline Precision_t &At(uint64 i, int32 j) {
|
|
DEBUG_ASSERT_MSG(i<num_of_points_,
|
|
"Attempt to acces data out of range %lli>%lli",
|
|
(unsigned long long)i,
|
|
(unsigned long long)num_of_points_);
|
|
DEBUG_ASSERT_MSG(j<dimension_,
|
|
"Attempt to access element greater that the dimension %lli>%lli",
|
|
(unsigned long long)j,
|
|
(unsigned long long)dimension_);
|
|
return data_[i*dimension_+j];
|
|
}
|
|
// get the index at i point
|
|
inline uint64 get_id(index_t i) {
|
|
return index_[i];
|
|
}
|
|
// set id at point i
|
|
inline void set_id(index_t i, index_t value) {
|
|
index_[i]=value;
|
|
}
|
|
// get the number of points
|
|
uint64 get_num_of_points() {
|
|
return num_of_points_;
|
|
}
|
|
// get the dimension
|
|
int32 get_dimension() {
|
|
return dimension_;
|
|
}
|
|
// get the name of the data file
|
|
string get_data_file() {
|
|
return data_file_;
|
|
}
|
|
// get the index file
|
|
string get_index_file() {
|
|
return index_file_;
|
|
}
|
|
|
|
private:
|
|
// system page size
|
|
index_t page_size_;
|
|
// number of points on the data set
|
|
uint64 num_of_points_;
|
|
// dimension of the data
|
|
int32 dimension_;
|
|
// A pointer to the data
|
|
Precision_t *data_;
|
|
// A pointer to the index
|
|
uint64 *index_;
|
|
// data file name
|
|
string data_file_;
|
|
// index file name
|
|
string index_file_;
|
|
// Reads the dimension and the number of points from a
|
|
// data file
|
|
void ReadDimNumOfPointsFromFile(string file_name) {
|
|
FILE *fp=fopen(file_name.c_str(), "r");
|
|
if (unlikely(fp==NULL)) {
|
|
FATAL("Error :%s while reading %s\n",
|
|
strerror(errno), file_name.c_str());
|
|
}
|
|
if (unlikely(fread(&dimension_, sizeof(int32), 1, fp)!=1)) {
|
|
FATAL("Error :%s while reading %s\n",
|
|
strerror(errno), file_name.c_str());
|
|
}
|
|
fclose(fp);
|
|
struct stat info;
|
|
if (unlikely(stat(file_name.c_str(), &info)!=0)) {
|
|
FATAL("Error %s file %s\n",
|
|
strerror(errno), file_name.c_str());
|
|
}
|
|
num_of_points_ = (info.st_size-sizeof(int32))/
|
|
(dimension_*sizeof(Precision_t));
|
|
}
|
|
// utility function for mapping a file
|
|
// offset is used for datafile where we have to read the
|
|
// dimension and map the rest of the file
|
|
// while in the index file we set it to zero
|
|
void* MemoryMap(string file_name, uint64 offset) {
|
|
struct stat info;
|
|
if (unlikely(stat(file_name.c_str(), &info)!=0)) {
|
|
FATAL("Error %s file %s\n",
|
|
strerror(errno), file_name.c_str());
|
|
}
|
|
uint64 map_size = info.st_size;
|
|
int fp=open(file_name.c_str(), O_RDWR);
|
|
if (fp<0) {
|
|
FATAL("Cannot open %s, error %s\n", file_name.c_str(), strerror(errno));
|
|
}
|
|
void *ptr=mmap(0,
|
|
map_size,
|
|
PROT_READ | PROT_WRITE, MAP_SHARED,
|
|
fp,
|
|
0);
|
|
ptr = (void*) ((char*)ptr+offset);
|
|
if (unlikely(ptr==MAP_FAILED)) {
|
|
FATAL("Error %s while mapping %s\n",
|
|
strerror(errno), file_name.c_str());
|
|
}
|
|
close(fp);
|
|
return ptr;
|
|
}
|
|
// same as the above for unmapping
|
|
success_t MemoryUnmap(void *ptr, string file_name, uint64 offset) {
|
|
struct stat info;
|
|
if (unlikely(stat(file_name.c_str(), &info)!=0)) {
|
|
NONFATAL("Error %s file %s\n",
|
|
strerror(errno), file_name.c_str());
|
|
return SUCCESS_FAIL;
|
|
}
|
|
uint64 map_size = info.st_size;
|
|
ptr = (char *)ptr-offset;
|
|
if(munmap(ptr , map_size)<0) {
|
|
NONFATAL("Error %s while unmapping %s\n",
|
|
strerror(errno), file_name.c_str());
|
|
return SUCCESS_FAIL;
|
|
}
|
|
return SUCCESS_PASS;
|
|
|
|
}
|
|
// creates a data file
|
|
void CreateDataFile(string file_name,
|
|
int32 dimension,
|
|
uint64 num_of_points) {
|
|
FILE *fp=fopen(file_name.c_str(), "w");
|
|
if (unlikely(fwrite(&dimension, sizeof(int32), 1, fp)!=1)) {
|
|
FATAL("Error %s, while writing for file %s\n",
|
|
strerror(errno), file_name.c_str());
|
|
}
|
|
uint64 total_size = num_of_points * dimension * sizeof(Precision_t);
|
|
const uint64 buffer_length=8192;
|
|
char *buffer=new char[buffer_length];
|
|
for(uint64 i=0; i<total_size/buffer_length; i++) {
|
|
if (unlikely(fwrite(buffer, 1, buffer_length, fp)!=buffer_length))
|
|
FATAL("Error %s, while writing for file %s\n",
|
|
strerror(errno), file_name.c_str());
|
|
}
|
|
if (unlikely(fwrite(buffer, 1, total_size % buffer_length, fp)!=
|
|
total_size % buffer_length)) {
|
|
FATAL("Error %s, while writing for file %s\n",
|
|
strerror(errno), file_name.c_str());
|
|
}
|
|
fclose(fp);
|
|
}
|
|
|
|
// creates an index file
|
|
void CreateIndexFile(string file_name,
|
|
uint64 num_of_points) {
|
|
FILE *fp=fopen(file_name.c_str(), "w");
|
|
uint64 total_size = num_of_points * sizeof(uint64);
|
|
const uint64 buffer_length=8192;
|
|
char *buffer=new char[buffer_length];
|
|
for(uint64 i=0; i<total_size/buffer_length; i++) {
|
|
if (unlikely(fwrite(buffer, 1, buffer_length, fp)!=buffer_length)) {
|
|
FATAL("Error %s, while writing for file %s\n",
|
|
strerror(errno), file_name.c_str());
|
|
}
|
|
}
|
|
if (unlikely(fwrite(buffer, 1, total_size % buffer_length, fp)!=
|
|
total_size % buffer_length)) {
|
|
FATAL("Error %s, while writing for file %s\n",
|
|
strerror(errno), file_name.c_str());
|
|
}
|
|
fclose(fp);
|
|
}
|
|
|
|
void Advise1(void *feed, index_t start, index_t num_of_bytes) {
|
|
index_t num_of_pages = (index_t)ceil(1.0*num_of_bytes/page_size_);
|
|
if (num_of_pages<kMinimumPagesToAdvise) {
|
|
return;
|
|
}
|
|
char *ptr =(char *)feed+start;
|
|
char *temp=NULL;
|
|
ptr =temp + ((ptrdiff_t)feed/page_size_)*page_size_;
|
|
if (unlikely(madvise(ptr, num_of_pages, MADV_WILLNEED)==-1)) {
|
|
FATAL("Failed to advise, error %s", strerror(errno));
|
|
}
|
|
}
|
|
void Advise2(void *feed, index_t start, index_t num_of_bytes) {
|
|
index_t num_of_pages = (index_t)floor(1.0*num_of_bytes/page_size_);
|
|
if (num_of_pages<kMinimumPagesToAdvise) {
|
|
return;
|
|
}
|
|
char *ptr =(char*)feed+start;
|
|
char *temp=NULL;
|
|
ptr =temp + (ptrdiff_t)ceil((ptrdiff_t)feed/page_size_)*page_size_;
|
|
if (unlikely(madvise(ptr, num_of_pages, MADV_WILLNEED)==-1)) {
|
|
FATAL("Failed to advise, error %s", strerror(errno));
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
#endif // BINARY_DATASET_H_
|