The new class cUnbufferedFile is used for the recording files to avoid thrashing the file system cache

This commit is contained in:
Klaus Schmidinger 2005-10-31 13:14:26 +01:00
parent 998e3bd2c7
commit 697261c981
11 changed files with 217 additions and 69 deletions

View File

@ -1520,3 +1520,6 @@ Nicolas Huillard <nhuillard@e-dition.fr>
Patrick Fischer <patrick_fischer@gmx.de> Patrick Fischer <patrick_fischer@gmx.de>
for reporting an error in the cFilter example in PLUGINS.html for reporting an error in the cFilter example in PLUGINS.html
Ralf Müller <ralf@bj-ig.de>
for a patch that was used to implement cUnbufferedFile

View File

@ -3886,7 +3886,7 @@ Video Disk Recorder Revision History
- The 'sub-title' and 'bottom text' in the CAM menu can now consist of several lines. - The 'sub-title' and 'bottom text' in the CAM menu can now consist of several lines.
- Improved the CAM enquiry menu. - Improved the CAM enquiry menu.
2005-10-30: Version 1.3.35 2005-10-31: Version 1.3.35
- Updated 'sources.conf' (thanks to Philip Prindeville). - Updated 'sources.conf' (thanks to Philip Prindeville).
- Now using daemon() instead of fork() to run VDR in daemon mode (thanks to - Now using daemon() instead of fork() to run VDR in daemon mode (thanks to
@ -3910,3 +3910,5 @@ Video Disk Recorder Revision History
- Updated the Greek OSD texts (thanks to Dimitrios Dimitrakos). - Updated the Greek OSD texts (thanks to Dimitrios Dimitrakos).
- Updated the French OSD texts (thanks to Nicolas Huillard). - Updated the French OSD texts (thanks to Nicolas Huillard).
- Fixed the cFilter example in PLUGINS.html (reported by Patrick Fischer). - Fixed the cFilter example in PLUGINS.html (reported by Patrick Fischer).
- The new class cUnbufferedFile is used for the recording files to avoid
trashing the file system cache (based on a patch by Ralf Müller).

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: cutter.c 1.10 2005/08/14 10:51:54 kls Exp $ * $Id: cutter.c 1.11 2005/10/31 12:26:44 kls Exp $
*/ */
#include "cutter.h" #include "cutter.h"
@ -18,7 +18,7 @@
class cCuttingThread : public cThread { class cCuttingThread : public cThread {
private: private:
const char *error; const char *error;
int fromFile, toFile; cUnbufferedFile *fromFile, *toFile;
cFileName *fromFileName, *toFileName; cFileName *fromFileName, *toFileName;
cIndexFile *fromIndex, *toIndex; cIndexFile *fromIndex, *toIndex;
cMarks fromMarks, toMarks; cMarks fromMarks, toMarks;
@ -34,7 +34,7 @@ cCuttingThread::cCuttingThread(const char *FromFileName, const char *ToFileName)
:cThread("video cutting") :cThread("video cutting")
{ {
error = NULL; error = NULL;
fromFile = toFile = -1; fromFile = toFile = NULL;
fromFileName = toFileName = NULL; fromFileName = toFileName = NULL;
fromIndex = toIndex = NULL; fromIndex = toIndex = NULL;
if (fromMarks.Load(FromFileName) && fromMarks.Count()) { if (fromMarks.Load(FromFileName) && fromMarks.Count()) {
@ -64,7 +64,7 @@ void cCuttingThread::Action(void)
if (Mark) { if (Mark) {
fromFile = fromFileName->Open(); fromFile = fromFileName->Open();
toFile = toFileName->Open(); toFile = toFileName->Open();
if (fromFile < 0 || toFile < 0) if (!fromFile || !toFile)
return; return;
int Index = Mark->position; int Index = Mark->position;
Mark = fromMarks.Next(Mark); Mark = fromMarks.Next(Mark);
@ -92,7 +92,7 @@ void cCuttingThread::Action(void)
fromFile = fromFileName->SetOffset(FileNumber, FileOffset); fromFile = fromFileName->SetOffset(FileNumber, FileOffset);
CurrentFileNumber = FileNumber; CurrentFileNumber = FileNumber;
} }
if (fromFile >= 0) { if (fromFile) {
int len = ReadFrame(fromFile, buffer, Length, sizeof(buffer)); int len = ReadFrame(fromFile, buffer, Length, sizeof(buffer));
if (len < 0) { if (len < 0) {
error = "ReadFrame"; error = "ReadFrame";
@ -131,7 +131,7 @@ void cCuttingThread::Action(void)
cutIn = false; cutIn = false;
} }
} }
if (safe_write(toFile, buffer, Length) < 0) { if (toFile->Write(buffer, Length) < 0) {
error = "safe_write"; error = "safe_write";
break; break;
} }

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: dvbplayer.c 1.40 2005/08/29 15:43:30 kls Exp $ * $Id: dvbplayer.c 1.41 2005/10/31 12:33:48 kls Exp $
*/ */
#include "dvbplayer.h" #include "dvbplayer.h"
@ -74,7 +74,7 @@ int cBackTrace::Get(bool Forward)
class cNonBlockingFileReader : public cThread { class cNonBlockingFileReader : public cThread {
private: private:
int f; cUnbufferedFile *f;
uchar *buffer; uchar *buffer;
int wanted; int wanted;
int length; int length;
@ -86,14 +86,14 @@ public:
cNonBlockingFileReader(void); cNonBlockingFileReader(void);
~cNonBlockingFileReader(); ~cNonBlockingFileReader();
void Clear(void); void Clear(void);
int Read(int FileHandle, uchar *Buffer, int Length); int Read(cUnbufferedFile *File, uchar *Buffer, int Length);
bool Reading(void) { return buffer; } bool Reading(void) { return buffer; }
}; };
cNonBlockingFileReader::cNonBlockingFileReader(void) cNonBlockingFileReader::cNonBlockingFileReader(void)
:cThread("non blocking file reader") :cThread("non blocking file reader")
{ {
f = -1; f = NULL;
buffer = NULL; buffer = NULL;
wanted = length = 0; wanted = length = 0;
hasData = false; hasData = false;
@ -110,7 +110,7 @@ cNonBlockingFileReader::~cNonBlockingFileReader()
void cNonBlockingFileReader::Clear(void) void cNonBlockingFileReader::Clear(void)
{ {
Lock(); Lock();
f = -1; f = NULL;
free(buffer); free(buffer);
buffer = NULL; buffer = NULL;
wanted = length = 0; wanted = length = 0;
@ -119,7 +119,7 @@ void cNonBlockingFileReader::Clear(void)
newSet.Signal(); newSet.Signal();
} }
int cNonBlockingFileReader::Read(int FileHandle, uchar *Buffer, int Length) int cNonBlockingFileReader::Read(cUnbufferedFile *File, uchar *Buffer, int Length)
{ {
if (hasData && buffer) { if (hasData && buffer) {
if (buffer != Buffer) { if (buffer != Buffer) {
@ -131,7 +131,7 @@ int cNonBlockingFileReader::Read(int FileHandle, uchar *Buffer, int Length)
return length; return length;
} }
if (!buffer) { if (!buffer) {
f = FileHandle; f = File;
buffer = Buffer; buffer = Buffer;
wanted = Length; wanted = Length;
length = 0; length = 0;
@ -146,8 +146,8 @@ void cNonBlockingFileReader::Action(void)
{ {
while (Running()) { while (Running()) {
Lock(); Lock();
if (!hasData && f >= 0 && buffer) { if (!hasData && f && buffer) {
int r = safe_read(f, buffer + length, wanted - length); int r = f->Read(buffer + length, wanted - length);
if (r >= 0) { if (r >= 0) {
length += r; length += r;
if (!r || length == wanted) // r == 0 means EOF if (!r || length == wanted) // r == 0 means EOF
@ -181,7 +181,7 @@ private:
cBackTrace *backTrace; cBackTrace *backTrace;
cFileName *fileName; cFileName *fileName;
cIndexFile *index; cIndexFile *index;
int replayFile; cUnbufferedFile *replayFile;
bool eof; bool eof;
bool firstPacket; bool firstPacket;
ePlayModes playMode; ePlayModes playMode;
@ -237,7 +237,7 @@ cDvbPlayer::cDvbPlayer(const char *FileName)
isyslog("replay %s", FileName); isyslog("replay %s", FileName);
fileName = new cFileName(FileName, false); fileName = new cFileName(FileName, false);
replayFile = fileName->Open(); replayFile = fileName->Open();
if (replayFile < 0) if (!replayFile)
return; return;
ringBuffer = new cRingBufferFrame(PLAYERBUFSIZE); ringBuffer = new cRingBufferFrame(PLAYERBUFSIZE);
// Create the index file: // Create the index file:
@ -302,10 +302,10 @@ bool cDvbPlayer::NextFile(uchar FileNumber, int FileOffset)
{ {
if (FileNumber > 0) if (FileNumber > 0)
replayFile = fileName->SetOffset(FileNumber, FileOffset); replayFile = fileName->SetOffset(FileNumber, FileOffset);
else if (replayFile >= 0 && eof) else if (replayFile && eof)
replayFile = fileName->NextFile(); replayFile = fileName->NextFile();
eof = false; eof = false;
return replayFile >= 0; return replayFile != NULL;
} }
int cDvbPlayer::Resume(void) int cDvbPlayer::Resume(void)
@ -342,7 +342,7 @@ bool cDvbPlayer::Save(void)
void cDvbPlayer::Activate(bool On) void cDvbPlayer::Activate(bool On)
{ {
if (On) { if (On) {
if (replayFile >= 0) if (replayFile)
Start(); Start();
} }
else else
@ -376,7 +376,7 @@ void cDvbPlayer::Action(void)
// Read the next frame from the file: // Read the next frame from the file:
if (playMode != pmStill && playMode != pmPause) { if (playMode != pmStill && playMode != pmPause) {
if (!readFrame && (replayFile >= 0 || readIndex >= 0)) { if (!readFrame && (replayFile || readIndex >= 0)) {
if (!nonBlockingFileReader->Reading()) { if (!nonBlockingFileReader->Reading()) {
if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) { if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) {
uchar FileNumber; uchar FileNumber;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: recorder.c 1.15 2005/08/14 10:53:28 kls Exp $ * $Id: recorder.c 1.16 2005/10/31 12:35:29 kls Exp $
*/ */
#include <stdarg.h> #include <stdarg.h>
@ -28,7 +28,7 @@ private:
cIndexFile *index; cIndexFile *index;
uchar pictureType; uchar pictureType;
int fileSize; int fileSize;
int recordFile; cUnbufferedFile *recordFile;
time_t lastDiskSpaceCheck; time_t lastDiskSpaceCheck;
bool RunningLowOnDiskSpace(void); bool RunningLowOnDiskSpace(void);
bool NextFile(void); bool NextFile(void);
@ -50,7 +50,7 @@ cFileWriter::cFileWriter(const char *FileName, cRemux *Remux)
lastDiskSpaceCheck = time(NULL); lastDiskSpaceCheck = time(NULL);
fileName = new cFileName(FileName, true); fileName = new cFileName(FileName, true);
recordFile = fileName->Open(); recordFile = fileName->Open();
if (recordFile < 0) if (!recordFile)
return; return;
// Create the index file: // Create the index file:
index = new cIndexFile(FileName, true); index = new cIndexFile(FileName, true);
@ -81,13 +81,13 @@ bool cFileWriter::RunningLowOnDiskSpace(void)
bool cFileWriter::NextFile(void) bool cFileWriter::NextFile(void)
{ {
if (recordFile >= 0 && pictureType == I_FRAME) { // every file shall start with an I_FRAME if (recordFile && pictureType == I_FRAME) { // every file shall start with an I_FRAME
if (fileSize > MEGABYTE(Setup.MaxVideoFileSize) || RunningLowOnDiskSpace()) { if (fileSize > MEGABYTE(Setup.MaxVideoFileSize) || RunningLowOnDiskSpace()) {
recordFile = fileName->NextFile(); recordFile = fileName->NextFile();
fileSize = 0; fileSize = 0;
} }
} }
return recordFile >= 0; return recordFile != NULL;
} }
void cFileWriter::Action(void) void cFileWriter::Action(void)
@ -102,7 +102,7 @@ void cFileWriter::Action(void)
if (NextFile()) { if (NextFile()) {
if (index && pictureType != NO_PICTURE) if (index && pictureType != NO_PICTURE)
index->Write(pictureType, fileName->Number(), fileSize); index->Write(pictureType, fileName->Number(), fileSize);
if (safe_write(recordFile, p, Count) < 0) { if (recordFile->Write(p, Count) < 0) {
LOG_ERROR_STR(fileName->Name()); LOG_ERROR_STR(fileName->Name());
break; break;
} }

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: recording.c 1.121 2005/10/09 13:09:51 kls Exp $ * $Id: recording.c 1.122 2005/10/31 12:27:58 kls Exp $
*/ */
#include "recording.h" #include "recording.h"
@ -1258,7 +1258,7 @@ int cIndexFile::Get(uchar FileNumber, int FileOffset)
cFileName::cFileName(const char *FileName, bool Record, bool Blocking) cFileName::cFileName(const char *FileName, bool Record, bool Blocking)
{ {
file = -1; file = NULL;
fileNumber = 0; fileNumber = 0;
record = Record; record = Record;
blocking = Blocking; blocking = Blocking;
@ -1279,21 +1279,21 @@ cFileName::~cFileName()
free(fileName); free(fileName);
} }
int cFileName::Open(void) cUnbufferedFile *cFileName::Open(void)
{ {
if (file < 0) { if (!file) {
int BlockingFlag = blocking ? 0 : O_NONBLOCK; int BlockingFlag = blocking ? 0 : O_NONBLOCK;
if (record) { if (record) {
dsyslog("recording to '%s'", fileName); dsyslog("recording to '%s'", fileName);
file = OpenVideoFile(fileName, O_RDWR | O_CREAT | BlockingFlag); file = OpenVideoFile(fileName, O_RDWR | O_CREAT | BlockingFlag);
if (file < 0) if (!file)
LOG_ERROR_STR(fileName); LOG_ERROR_STR(fileName);
} }
else { else {
if (access(fileName, R_OK) == 0) { if (access(fileName, R_OK) == 0) {
dsyslog("playing '%s'", fileName); dsyslog("playing '%s'", fileName);
file = open(fileName, O_RDONLY | BlockingFlag); file = cUnbufferedFile::Create(fileName, O_RDONLY | BlockingFlag);
if (file < 0) if (!file)
LOG_ERROR_STR(fileName); LOG_ERROR_STR(fileName);
} }
else if (errno != ENOENT) else if (errno != ENOENT)
@ -1305,14 +1305,14 @@ int cFileName::Open(void)
void cFileName::Close(void) void cFileName::Close(void)
{ {
if (file >= 0) { if (file) {
if ((record && CloseVideoFile(file) < 0) || (!record && close(file) < 0)) if ((record && CloseVideoFile(file) < 0) || (!record && file->Close() < 0))
LOG_ERROR_STR(fileName); LOG_ERROR_STR(fileName);
file = -1; file = NULL;
} }
} }
int cFileName::SetOffset(int Number, int Offset) cUnbufferedFile *cFileName::SetOffset(int Number, int Offset)
{ {
if (fileNumber != Number) if (fileNumber != Number)
Close(); Close();
@ -1337,23 +1337,23 @@ int cFileName::SetOffset(int Number, int Offset)
} }
else if (errno != ENOENT) { // something serious has happened else if (errno != ENOENT) { // something serious has happened
LOG_ERROR_STR(fileName); LOG_ERROR_STR(fileName);
return -1; return NULL;
} }
// found a non existing file suffix // found a non existing file suffix
} }
if (Open() >= 0) { if (Open() >= 0) {
if (!record && Offset >= 0 && lseek(file, Offset, SEEK_SET) != Offset) { if (!record && Offset >= 0 && file->Seek(Offset, SEEK_SET) != Offset) {
LOG_ERROR_STR(fileName); LOG_ERROR_STR(fileName);
return -1; return NULL;
} }
} }
return file; return file;
} }
esyslog("ERROR: max number of files (%d) exceeded", MAXFILESPERRECORDING); esyslog("ERROR: max number of files (%d) exceeded", MAXFILESPERRECORDING);
return -1; return NULL;
} }
int cFileName::NextFile(void) cUnbufferedFile *cFileName::NextFile(void)
{ {
return SetOffset(fileNumber + 1); return SetOffset(fileNumber + 1);
} }
@ -1387,7 +1387,7 @@ int SecondsToFrames(int Seconds)
// --- ReadFrame ------------------------------------------------------------- // --- ReadFrame -------------------------------------------------------------
int ReadFrame(int f, uchar *b, int Length, int Max) int ReadFrame(cUnbufferedFile *f, uchar *b, int Length, int Max)
{ {
if (Length == -1) if (Length == -1)
Length = Max; // this means we read up to EOF (see cIndex) Length = Max; // this means we read up to EOF (see cIndex)
@ -1395,10 +1395,8 @@ int ReadFrame(int f, uchar *b, int Length, int Max)
esyslog("ERROR: frame larger than buffer (%d > %d)", Length, Max); esyslog("ERROR: frame larger than buffer (%d > %d)", Length, Max);
Length = Max; Length = Max;
} }
int r = safe_read(f, b, Length); int r = f->Read(b, Length);
if (r < 0) if (r < 0)
LOG_ERROR; LOG_ERROR;
return r; return r;
} }

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: recording.h 1.45 2005/10/01 10:24:41 kls Exp $ * $Id: recording.h 1.46 2005/10/31 12:27:12 kls Exp $
*/ */
#ifndef __RECORDING_H #ifndef __RECORDING_H
@ -203,7 +203,7 @@ public:
class cFileName { class cFileName {
private: private:
int file; cUnbufferedFile *file;
int fileNumber; int fileNumber;
char *fileName, *pFileNumber; char *fileName, *pFileNumber;
bool record; bool record;
@ -213,10 +213,10 @@ public:
~cFileName(); ~cFileName();
const char *Name(void) { return fileName; } const char *Name(void) { return fileName; }
int Number(void) { return fileNumber; } int Number(void) { return fileNumber; }
int Open(void); cUnbufferedFile *Open(void);
void Close(void); void Close(void);
int SetOffset(int Number, int Offset = 0); cUnbufferedFile *SetOffset(int Number, int Offset = 0);
int NextFile(void); cUnbufferedFile *NextFile(void);
}; };
cString IndexToHMSF(int Index, bool WithFrame = false); cString IndexToHMSF(int Index, bool WithFrame = false);
@ -226,7 +226,7 @@ int HMSFToIndex(const char *HMSF);
int SecondsToFrames(int Seconds); //XXX+ ->player??? int SecondsToFrames(int Seconds); //XXX+ ->player???
// Returns the number of frames corresponding to the given number of seconds. // Returns the number of frames corresponding to the given number of seconds.
int ReadFrame(int f, uchar *b, int Length, int Max); int ReadFrame(cUnbufferedFile *f, uchar *b, int Length, int Max);
char *ExchangeChars(char *s, bool ToFileSystem); char *ExchangeChars(char *s, bool ToFileSystem);
// Exchanges the characters in the given string to or from a file system // Exchanges the characters in the given string to or from a file system

125
tools.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: tools.c 1.99 2005/09/25 12:56:06 kls Exp $ * $Id: tools.c 1.100 2005/10/31 12:56:15 kls Exp $
*/ */
#include "tools.h" #include "tools.h"
@ -836,6 +836,129 @@ bool cSafeFile::Close(void)
return result; return result;
} }
// --- cUnbufferedFile -------------------------------------------------------
#define READ_AHEAD MEGABYTE(2)
#define WRITE_BUFFER MEGABYTE(10)
cUnbufferedFile::cUnbufferedFile(void)
{
fd = -1;
}
cUnbufferedFile::~cUnbufferedFile()
{
Close();
}
int cUnbufferedFile::Open(const char *FileName, int Flags, mode_t Mode)
{
Close();
fd = open(FileName, Flags, Mode);
begin = end = ahead = -1;
written = 0;
return fd;
}
int cUnbufferedFile::Close(void)
{
if (fd >= 0) {
if (ahead > end)
end = ahead;
if (begin >= 0 && end > begin) {
//dsyslog("close buffer: %d (flush: %d bytes, %ld-%ld)", fd, written, begin, end);
if (written)
fdatasync(fd);
posix_fadvise(fd, begin, end - begin, POSIX_FADV_DONTNEED);
}
begin = end = ahead = -1;
written = 0;
}
int OldFd = fd;
fd = -1;
return close(OldFd);
}
off_t cUnbufferedFile::Seek(off_t Offset, int Whence)
{
if (fd >= 0)
return lseek(fd, Offset, Whence);
return -1;
}
ssize_t cUnbufferedFile::Read(void *Data, size_t Size)
{
if (fd >= 0) {
off_t pos = lseek(fd, 0, SEEK_CUR);
// jump forward - adjust end position
if (pos > end)
end = pos;
// after adjusting end - don't clear more than previously requested
if (end > ahead)
end = ahead;
// jump backward - drop read ahead of previous run
if (pos < begin)
end = ahead;
if (begin >= 0 && end > begin)
posix_fadvise(fd, begin - KILOBYTE(200), end - begin + KILOBYTE(200), POSIX_FADV_DONTNEED);//XXX macros/parameters???
begin = pos;
ssize_t bytesRead = safe_read(fd, Data, Size);
if (bytesRead > 0) {
pos += bytesRead;
end = pos;
// this seems to trigger a non blocking read - this
// may or may not have been finished when we will be called next time.
// If it is not finished we can't release the not yet filled buffers.
// So this is commented out till we find a better solution.
//posix_fadvise(fd, pos, READ_AHEAD, POSIX_FADV_WILLNEED);
ahead = pos + READ_AHEAD;
}
else
end = pos;
return bytesRead;
}
return -1;
}
ssize_t cUnbufferedFile::Write(const void *Data, size_t Size)
{
if (fd >=0) {
off_t pos = lseek(fd, 0, SEEK_CUR);
ssize_t bytesWritten = safe_write(fd, Data, Size);
if (bytesWritten >= 0) {
written += bytesWritten;
if (begin >= 0) {
if (pos < begin)
begin = pos;
}
else
begin = pos;
if (pos + bytesWritten > end)
end = pos + bytesWritten;
if (written > WRITE_BUFFER) {
//dsyslog("flush buffer: %d (%d bytes, %ld-%ld)", fd, written, begin, end);
fdatasync(fd);
if (begin >= 0 && end > begin)
posix_fadvise(fd, begin, end - begin, POSIX_FADV_DONTNEED);
begin = end = -1;
written = 0;
}
}
return bytesWritten;
}
return -1;
}
cUnbufferedFile *cUnbufferedFile::Create(const char *FileName, int Flags, mode_t Mode)
{
cUnbufferedFile *File = new cUnbufferedFile;
if (File->Open(FileName, Flags, Mode) < 0) {
delete File;
File = NULL;
}
return File;
}
// --- cLockFile ------------------------------------------------------------- // --- cLockFile -------------------------------------------------------------
#define LOCKFILENAME ".lock-vdr" #define LOCKFILENAME ".lock-vdr"

23
tools.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: tools.h 1.80 2005/10/09 11:13:06 kls Exp $ * $Id: tools.h 1.81 2005/10/31 12:54:36 kls Exp $
*/ */
#ifndef __TOOLS_H #ifndef __TOOLS_H
@ -198,6 +198,27 @@ public:
bool Close(void); bool Close(void);
}; };
/// cUnbufferedFile is used for large files that are mainly written or read
/// in a streaming manner, and thus should not be cached.
class cUnbufferedFile {
private:
int fd;
off_t begin;
off_t end;
off_t ahead;
ssize_t written;
public:
cUnbufferedFile(void);
~cUnbufferedFile();
int Open(const char *FileName, int Flags, mode_t Mode = DEFFILEMODE);
int Close(void);
off_t Seek(off_t Offset, int Whence);
ssize_t Read(void *Data, size_t Size);
ssize_t Write(const void *Data, size_t Size);
static cUnbufferedFile *Create(const char *FileName, int Flags, mode_t Mode = DEFFILEMODE);
};
class cLockFile { class cLockFile {
private: private:
char *fileName; char *fileName;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: videodir.c 1.12 2005/08/06 09:53:21 kls Exp $ * $Id: videodir.c 1.13 2005/10/31 12:07:41 kls Exp $
*/ */
#include "videodir.h" #include "videodir.h"
@ -102,7 +102,7 @@ const char *cVideoDirectory::Adjust(const char *FileName)
return NULL; return NULL;
} }
int OpenVideoFile(const char *FileName, int Flags) cUnbufferedFile *OpenVideoFile(const char *FileName, int Flags)
{ {
const char *ActualFileName = FileName; const char *ActualFileName = FileName;
@ -110,7 +110,7 @@ int OpenVideoFile(const char *FileName, int Flags)
if (strstr(FileName, VideoDirectory) != FileName) { if (strstr(FileName, VideoDirectory) != FileName) {
esyslog("ERROR: %s not in %s", FileName, VideoDirectory); esyslog("ERROR: %s not in %s", FileName, VideoDirectory);
errno = ENOENT; // must set 'errno' - any ideas for a better value? errno = ENOENT; // must set 'errno' - any ideas for a better value?
return -1; return NULL;
} }
// Are we going to create a new file? // Are we going to create a new file?
if ((Flags & O_CREAT) != 0) { if ((Flags & O_CREAT) != 0) {
@ -128,25 +128,26 @@ int OpenVideoFile(const char *FileName, int Flags)
if (Dir.Stored()) { if (Dir.Stored()) {
ActualFileName = Dir.Adjust(FileName); ActualFileName = Dir.Adjust(FileName);
if (!MakeDirs(ActualFileName, false)) if (!MakeDirs(ActualFileName, false))
return -1; // errno has been set by MakeDirs() return NULL; // errno has been set by MakeDirs()
if (symlink(ActualFileName, FileName) < 0) { if (symlink(ActualFileName, FileName) < 0) {
LOG_ERROR_STR(FileName); LOG_ERROR_STR(FileName);
return -1; return NULL;
} }
ActualFileName = strdup(ActualFileName); // must survive Dir! ActualFileName = strdup(ActualFileName); // must survive Dir!
} }
} }
} }
int Result = open(ActualFileName, Flags, DEFFILEMODE); cUnbufferedFile *File = cUnbufferedFile::Create(ActualFileName, Flags, DEFFILEMODE);
if (ActualFileName != FileName) if (ActualFileName != FileName)
free((char *)ActualFileName); free((char *)ActualFileName);
return Result; return File;
} }
int CloseVideoFile(int FileHandle) int CloseVideoFile(cUnbufferedFile *File)
{ {
// just in case we ever decide to do something special when closing the file! int Result = File->Close();
return close(FileHandle); delete File;
return Result;
} }
bool RenameVideoFile(const char *OldName, const char *NewName) bool RenameVideoFile(const char *OldName, const char *NewName)

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: videodir.h 1.5 2004/12/26 11:52:56 kls Exp $ * $Id: videodir.h 1.6 2005/10/31 11:50:23 kls Exp $
*/ */
#ifndef __VIDEODIR_H #ifndef __VIDEODIR_H
@ -15,8 +15,8 @@
extern const char *VideoDirectory; extern const char *VideoDirectory;
int OpenVideoFile(const char *FileName, int Flags); cUnbufferedFile *OpenVideoFile(const char *FileName, int Flags);
int CloseVideoFile(int FileHandle); int CloseVideoFile(cUnbufferedFile *File);
bool RenameVideoFile(const char *OldName, const char *NewName); bool RenameVideoFile(const char *OldName, const char *NewName);
bool RemoveVideoFile(const char *FileName); bool RemoveVideoFile(const char *FileName);
bool VideoFileSpaceAvailable(int SizeMB); bool VideoFileSpaceAvailable(int SizeMB);