privacore-open-source-searc.../SiteMedianPageTemperatureRegistry.cpp

188 lines
4.8 KiB
C++

#include "SiteMedianPageTemperatureRegistry.h"
#include "ScopedLock.h"
#include "Log.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <algorithm>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
SiteMedianPageTemperatureRegistry g_smptr;
static GbMutex mtx;
static const char primary_filename[] = "site_median_page_temperatures.dat";
static const char secondary_filename[] = "site_median_page_temperatures.dat.new";
namespace {
struct Entry {
uint32_t sitehash32;
uint32_t default_pagerank;
};
}
bool SiteMedianPageTemperatureRegistry::open() {
ScopedLock sl(mtx);
int fd = ::open(primary_filename,O_RDWR|O_APPEND|O_CREAT,0666);
if(fd<0) {
log(LOG_ERROR,"open(%s) failed, errno=%d (%s)", primary_filename, errno, strerror(errno));
return false;
}
if(!load(fd,&primary_map,primary_filename)) {
::close(fd);
return false;
}
primary_fd = fd;
fd = ::open(secondary_filename,O_RDWR|O_APPEND);
if(fd>=0) {
if(!load(fd,&secondary_map,secondary_filename)) {
::close(fd);
::close(primary_fd);
primary_fd=-1;
primary_map.clear();
return false;
}
secondary_fd = fd;
} else if(errno==ENOENT) {
; //ok
} else {
log(LOG_ERROR,"open(%s) failed, errno=%d (%s)", secondary_filename, errno, strerror(errno));
return false;
}
return true;
}
bool SiteMedianPageTemperatureRegistry::load(int fd, std::map<uint32_t,unsigned> *m, const char *filename) {
log(LOG_INFO,"Loading %s", filename);
struct stat st;
if(fstat(fd,&st)!=0) {
log(LOG_ERROR,"fstat(%s) failed, errno=%d (%s)", filename, errno, strerror(errno));
::close(fd);
return false;
}
if(st.st_size%sizeof(Entry)) {
log(LOG_ERROR,"%s size is wrong", filename);
::close(fd);
return false;
}
static const size_t N=64*1024/sizeof(Entry);
Entry e[N];
for(;;) {
ssize_t bytes_read = read(fd, e, sizeof(e));
if(bytes_read<0) {
log(LOG_ERROR,"read(%s) failed, errno=%d (%s)", filename, errno, strerror(errno));
return false;
} else if(bytes_read==0) {
break; //eof
}
unsigned n = bytes_read/sizeof(Entry);
for(unsigned i=0; i<n; i++)
m->emplace(e[i].sitehash32,e[i].default_pagerank);
}
log(LOG_INFO,"Loaded %s", filename);
return true;
}
void SiteMedianPageTemperatureRegistry::close() {
if(primary_fd>=0) {
::close(primary_fd);
primary_fd = -1;
}
primary_map.clear();
if(secondary_fd>=0) {
::close(secondary_fd);
secondary_fd = -1;
}
secondary_map.clear();
}
bool SiteMedianPageTemperatureRegistry::lookup(uint32_t sitehash32, unsigned *default_site_page_temperature) const {
ScopedLock sl(mtx);
auto iter = primary_map.find(sitehash32);
if(iter!=primary_map.end()) {
*default_site_page_temperature = iter->second;
return true;
} else
return false;
}
bool SiteMedianPageTemperatureRegistry::add(uint32_t sitehash32, unsigned default_site_page_temperature) {
ScopedLock sl(mtx);
//if the value hasn't changed then there is no need for appending to the files
auto iter = primary_map.find(sitehash32);
if(iter!=primary_map.end() && iter->second==default_site_page_temperature)
return true;
Entry e;
e.sitehash32 = sitehash32;
e.default_pagerank = default_site_page_temperature;
ssize_t bytes_written;
bytes_written = write(primary_fd,&e,sizeof(e));
if(bytes_written!=sizeof(e)) {
log(LOG_ERROR,"Could not append to %s, errno=%d (%s)", primary_filename, errno, strerror(errno));
return false;
}
if(secondary_fd>=0) {
bytes_written = write(secondary_fd,&e,sizeof(e));
if(bytes_written!=sizeof(e)) {
log(LOG_ERROR,"Could not append to %s, errno=%d (%s)", secondary_filename, errno, strerror(errno));
return false;
}
}
primary_map[sitehash32] = default_site_page_temperature;
if(secondary_fd>=0)
secondary_map[sitehash32] = default_site_page_temperature;
return true;
}
bool SiteMedianPageTemperatureRegistry::prepare_new_generation() {
ScopedLock sl(mtx);
if(secondary_fd>=0) {
//preparing again means throwing away the current secondary
::close(secondary_fd);
secondary_fd = -1;
::unlink(secondary_filename);
secondary_map.clear();
}
secondary_fd = ::open(secondary_filename, O_RDWR|O_APPEND|O_CREAT|O_TRUNC,0666);
if(secondary_fd<0) {
log(LOG_ERROR,"open(%s) failed, errno=%d (%s)", secondary_filename, errno, strerror(errno));
return false;
}
return true;
}
void SiteMedianPageTemperatureRegistry::switch_generation() {
ScopedLock sl(mtx);
if(secondary_fd<0) {
log(LOG_WARN,"SiteMedianPageTemperatureRegistry::switch_generation() called, but there is no new generation in progress");
return;
}
if(::rename(secondary_filename,primary_filename)<0) {
log(LOG_ERROR,"rename(%s -> %s) failed, errno=%d (%s)", secondary_filename, primary_filename, errno, strerror(errno));
return;
}
::close(primary_fd);
primary_fd = secondary_fd;
secondary_fd = -1;
std::swap(primary_map,secondary_map);
secondary_map.clear();
}