#include "patchserver.h" #include <iostream> #include <algorithm> using namespace std; using namespace nxs; //TODO support compression! bool PatchServer::Create(const std::string &filename, Signature sig, unsigned int csize, unsigned int rsize) { signature = sig; chunk_size = csize; frame = 0; ram_size = rsize; ram_used = 0; lru.clear(); return File::Create(filename); } bool PatchServer::Load(const std::string &filename, Signature sig, unsigned int csize, bool readonly, unsigned int rsize) { signature = sig; chunk_size = csize; ram_size = rsize; frame = 0; ram_used = 0; lru.clear(); return File::Load(filename, readonly); } void PatchServer::Close() { FlushAll(); File::Close(); } //TODO add error checking. bool PatchServer::ReadEntries(FILE *fp) { unsigned int n; fread(&n, 1, sizeof(int), fp); patches.resize(n); for(unsigned int i = 0; i < n; i++) { patches[i].patch = NULL; fread(&(patches[i].patch_start), 1, sizeof(unsigned int), fp); fread(&(patches[i].patch_size), 1, sizeof(unsigned short), fp); fread(&(patches[i].ram_used), 1, sizeof(unsigned short), fp); patches[i].lru_pos = 0xffffffff; } return true; } bool PatchServer::WriteEntries(FILE *fp) { unsigned int n = patches.size(); fwrite(&n, 1, sizeof(int), fp); for(unsigned int i = 0; i < patches.size(); i++) { fwrite(&(patches[i].patch_start), 1, sizeof(unsigned int), fp); fwrite(&(patches[i].patch_size), 1, sizeof(unsigned short), fp); fwrite(&(patches[i].ram_used), 1, sizeof(unsigned short), fp); } return true; } void PatchServer::AddPatch(unsigned short nvert, unsigned short nface) { PatchEntry entry; entry.patch = NULL; entry.patch_start = Length()/chunk_size; entry.patch_size = Patch::ChunkSize(signature, nvert, nface, chunk_size); entry.ram_used = entry.patch_size; entry.lru_pos = 0xffffffff; patches.push_back(entry); Redim(Length() + entry.patch_size * chunk_size); } Patch &PatchServer::GetPatch(unsigned int idx, unsigned short nvert, unsigned short nface, bool flush) { assert(idx < patches.size()); PatchEntry &entry = patches[idx]; if(entry.patch) { assert(entry.lru_pos < lru.size()); assert(lru[entry.lru_pos].patch == idx); lru[entry.lru_pos].frame = frame++; } else { SetPosition(entry.patch_start * chunk_size); assert(entry.patch_size != 0); char *start = new char[entry.patch_size * chunk_size]; ReadBuffer(start, entry.patch_size * chunk_size); entry.patch = new Patch(signature, start, nvert, nface); entry.lru_pos = lru.size(); lru.push_back(PTime(idx, frame++)); ram_used += entry.ram_used; } //avoid frame overflow! if(frame > (1<<30)) { cerr << "oVERFLOW! (nothing dangerous... just warning." << endl;; for(unsigned int i = 0; i < lru.size(); i++) { if(lru[i].frame < (1<<29)) lru[i].frame = 0; else lru[i].frame -= (1<<29); } make_heap(lru.begin(), lru.end()); for(unsigned int i = 0; i < lru.size(); i++) patches[lru[i].patch].lru_pos = i; } if(flush && ram_used > ram_size * 1.1) Flush(); return *(entry.patch); } void PatchServer::Flush() { cerr << "FLUSHING\n\n\n n"; cerr << "ram_size: " << ram_size << endl; cerr << "ram_used: " << ram_used << endl; make_heap(lru.begin(), lru.end()); while(ram_used > ram_size) { pop_heap(lru.begin(), lru.end()); PTime &ptime = lru.back(); Flush(ptime.patch); lru.pop_back(); } make_heap(lru.begin(), lru.end()); for(unsigned int i = 0; i < lru.size(); i++) patches[lru[i].patch].lru_pos = i; } void PatchServer::FlushAll() { for(unsigned int i = 0; i < lru.size(); i++) { PTime &ptime = lru[i]; Flush(ptime.patch); } assert(ram_used == 0); lru.clear(); } void PatchServer::Flush(unsigned int patch) { PatchEntry &entry = patches[patch]; assert(entry.patch); if(!readonly) { //write back patch SetPosition(entry.patch_start * chunk_size); WriteBuffer(entry.patch->start, entry.patch_size * chunk_size); } delete [](entry.patch->start); delete entry.patch; entry.patch = NULL; entry.lru_pos = 0xffffffff; ram_used -= entry.ram_used; }