* Made a class FileMap from struct file_map.

* Added two TODO comments to the start of the file.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26287 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-07-07 11:16:50 +00:00
parent 62bf33df96
commit 9dcc2929fa
+166 -151
View File
@@ -30,9 +30,14 @@
# define TRACE(x) ; # define TRACE(x) ;
#endif #endif
// TODO: use a sparse array - eventually, the unused BlockMap would be something
// to reuse for this. We could also have an upperbound of memory consumption
// for the whole map.
// TODO: it would be nice if we could free a file map in low memory situations.
#define CACHED_FILE_EXTENTS 2 #define CACHED_FILE_EXTENTS 2
// must be smaller than MAX_FILE_IO_VECS // must be smaller than MAX_FILE_IO_VECS
// ToDo: find out how much of these are typically used // TODO: find out how much of these are typically used
struct file_extent { struct file_extent {
off_t offset; off_t offset;
@@ -40,76 +45,79 @@ struct file_extent {
}; };
struct file_extent_array { struct file_extent_array {
file_extent *array; file_extent* array;
size_t max_count; size_t max_count;
}; };
struct file_map { class FileMap {
file_map(off_t size); public:
~file_map(); FileMap(struct vnode* vnode, off_t size);
~FileMap();
file_extent *operator[](uint32 index); void Invalidate(off_t offset, off_t size);
file_extent *ExtentAt(uint32 index); void SetSize(off_t size);
file_extent *FindExtent(off_t offset, uint32 *_index); void Free();
status_t Add(file_io_vec *vecs, size_t vecCount, off_t &lastOffset);
void Invalidate(off_t offset, off_t size);
void Free();
status_t _MakeSpace(size_t amount); status_t Translate(off_t offset, size_t size,
file_io_vec* vecs, size_t* _count);
size_t Count() const { return fCount; }
struct vnode* Vnode() const { return fVnode; }
off_t Size() const { return fSize; }
private:
file_extent* _ExtentAt(uint32 index);
file_extent* _FindExtent(off_t offset, uint32* _index);
status_t _MakeSpace(size_t count);
status_t _Add(file_io_vec* vecs, size_t vecCount,
off_t& lastOffset);
union { union {
file_extent direct[CACHED_FILE_EXTENTS]; file_extent fDirect[CACHED_FILE_EXTENTS];
file_extent_array indirect; file_extent_array fIndirect;
}; };
size_t count; size_t fCount;
struct vnode *vnode; struct vnode* fVnode;
off_t size; off_t fSize;
}; };
file_map::file_map(off_t _size) FileMap::FileMap(struct vnode* vnode, off_t size)
{ {
indirect.array = NULL; fCount = 0;
count = 0; fVnode = vnode;
size = _size; fSize = size;
} }
file_map::~file_map() FileMap::~FileMap()
{ {
Free(); Free();
} }
file_extent * file_extent*
file_map::operator[](uint32 index) FileMap::_ExtentAt(uint32 index)
{ {
return ExtentAt(index); if (index >= fCount)
}
file_extent *
file_map::ExtentAt(uint32 index)
{
if (index >= count)
return NULL; return NULL;
if (count > CACHED_FILE_EXTENTS) if (fCount > CACHED_FILE_EXTENTS)
return &indirect.array[index]; return &fIndirect.array[index];
return &direct[index]; return &fDirect[index];
} }
file_extent * file_extent*
file_map::FindExtent(off_t offset, uint32 *_index) FileMap::_FindExtent(off_t offset, uint32 *_index)
{ {
int32 left = 0; int32 left = 0;
int32 right = count - 1; int32 right = fCount - 1;
while (left <= right) { while (left <= right) {
int32 index = (left + right) / 2; int32 index = (left + right) / 2;
file_extent *extent = ExtentAt(index); file_extent* extent = _ExtentAt(index);
if (extent->offset > offset) { if (extent->offset > offset) {
// search in left part // search in left part
@@ -131,67 +139,67 @@ file_map::FindExtent(off_t offset, uint32 *_index)
status_t status_t
file_map::_MakeSpace(size_t amount) FileMap::_MakeSpace(size_t count)
{ {
if (amount <= CACHED_FILE_EXTENTS) { if (count <= CACHED_FILE_EXTENTS) {
// just use the reserved area in the file_cache_ref structure // just use the reserved area in the file_cache_ref structure
if (amount <= CACHED_FILE_EXTENTS && count > CACHED_FILE_EXTENTS) { if (count <= CACHED_FILE_EXTENTS && fCount > CACHED_FILE_EXTENTS) {
// the new size is smaller than the minimal array size // the new size is smaller than the minimal array size
file_extent *array = indirect.array; file_extent *array = fIndirect.array;
memcpy(direct, array, sizeof(file_extent) * amount); memcpy(fDirect, array, sizeof(file_extent) * count);
free(array); free(array);
} }
} else { } else {
// resize array if needed // resize array if needed
file_extent *oldArray = NULL; file_extent* oldArray = NULL;
size_t maxCount = CACHED_FILE_EXTENTS; size_t maxCount = CACHED_FILE_EXTENTS;
if (count > CACHED_FILE_EXTENTS) { if (fCount > CACHED_FILE_EXTENTS) {
oldArray = indirect.array; oldArray = fIndirect.array;
maxCount = indirect.max_count; maxCount = fIndirect.max_count;
} }
if (amount > maxCount) { if (count > maxCount) {
// allocate new array // allocate new array
while (maxCount < amount) { while (maxCount < count) {
if (maxCount < 32768) if (maxCount < 32768)
maxCount <<= 1; maxCount <<= 1;
else else
maxCount += 32768; maxCount += 32768;
} }
file_extent *newArray = (file_extent *)realloc(oldArray, file_extent* newArray = (file_extent *)realloc(oldArray,
maxCount * sizeof(file_extent)); maxCount * sizeof(file_extent));
if (newArray == NULL) if (newArray == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
if (count > 0 && count <= CACHED_FILE_EXTENTS) if (fCount > 0 && fCount <= CACHED_FILE_EXTENTS)
memcpy(newArray, direct, sizeof(file_extent) * count); memcpy(newArray, fDirect, sizeof(file_extent) * fCount);
indirect.array = newArray; fIndirect.array = newArray;
indirect.max_count = maxCount; fIndirect.max_count = maxCount;
} }
} }
count = amount; fCount = count;
return B_OK; return B_OK;
} }
status_t status_t
file_map::Add(file_io_vec *vecs, size_t vecCount, off_t &lastOffset) FileMap::_Add(file_io_vec* vecs, size_t vecCount, off_t& lastOffset)
{ {
TRACE(("file_map@%p::Add(vecCount = %ld)\n", this, vecCount)); TRACE(("FileMap@%p::Add(vecCount = %ld)\n", this, vecCount));
uint32 start = count; uint32 start = fCount;
off_t offset = 0; off_t offset = 0;
status_t status = _MakeSpace(count + vecCount); status_t status = _MakeSpace(fCount + vecCount);
if (status != B_OK) if (status != B_OK)
return status; return status;
file_extent *lastExtent = NULL; file_extent* lastExtent = NULL;
if (start != 0) { if (start != 0) {
lastExtent = ExtentAt(start - 1); lastExtent = _ExtentAt(start - 1);
offset = lastExtent->offset + lastExtent->disk.length; offset = lastExtent->offset + lastExtent->disk.length;
} }
@@ -202,12 +210,12 @@ file_map::Add(file_io_vec *vecs, size_t vecCount, off_t &lastOffset)
lastExtent->disk.length += vecs[i].length; lastExtent->disk.length += vecs[i].length;
offset += vecs[i].length; offset += vecs[i].length;
start--; start--;
_MakeSpace(count - 1); _MakeSpace(fCount - 1);
continue; continue;
} }
} }
file_extent *extent = ExtentAt(start + i); file_extent* extent = _ExtentAt(start + i);
extent->offset = offset; extent->offset = offset;
extent->disk = vecs[i]; extent->disk = vecs[i];
@@ -216,8 +224,8 @@ file_map::Add(file_io_vec *vecs, size_t vecCount, off_t &lastOffset)
} }
#ifdef TRACE_FILE_MAP #ifdef TRACE_FILE_MAP
for (uint32 i = 0; i < count; i++) { for (uint32 i = 0; i < fCount; i++) {
file_extent *extent = ExtentAt(i); file_extent* extent = _ExtentAt(i);
dprintf("[%ld] extent offset %Ld, disk offset %Ld, length %Ld\n", dprintf("[%ld] extent offset %Ld, disk offset %Ld, length %Ld\n",
i, extent->offset, extent->disk.offset, extent->disk.length); i, extent->offset, extent->disk.offset, extent->disk.length);
} }
@@ -231,7 +239,7 @@ file_map::Add(file_io_vec *vecs, size_t vecCount, off_t &lastOffset)
/*! Invalidates or removes the specified part of the file map. /*! Invalidates or removes the specified part of the file map.
*/ */
void void
file_map::Invalidate(off_t offset, off_t size) FileMap::Invalidate(off_t offset, off_t size)
{ {
// TODO: honour size, we currently always remove everything after "offset" // TODO: honour size, we currently always remove everything after "offset"
if (offset == 0) { if (offset == 0) {
@@ -240,7 +248,7 @@ file_map::Invalidate(off_t offset, off_t size)
} }
uint32 index; uint32 index;
file_extent *extent = FindExtent(offset, &index); file_extent* extent = _FindExtent(offset, &index);
if (extent != NULL) { if (extent != NULL) {
_MakeSpace(index); _MakeSpace(index);
@@ -251,104 +259,44 @@ file_map::Invalidate(off_t offset, off_t size)
void void
file_map::Free() FileMap::SetSize(off_t size)
{ {
if (count > CACHED_FILE_EXTENTS) if (size < fSize)
free(indirect.array); Invalidate(size, fSize - size);
count = 0; fSize = size;
} }
// #pragma mark - public FS API void
FileMap::Free()
extern "C" void *
file_map_create(dev_t mountID, ino_t vnodeID, off_t size)
{ {
TRACE(("file_map_create(mountID = %ld, vnodeID = %Ld, size = %Ld)\n", if (fCount > CACHED_FILE_EXTENTS)
mountID, vnodeID, size)); free(fIndirect.array);
file_map *map = new file_map(size); fCount = 0;
if (map == NULL)
return NULL;
// Get the vnode for the object
// (note, this does not grab a reference to the node)
if (vfs_lookup_vnode(mountID, vnodeID, &map->vnode) != B_OK) {
delete map;
return NULL;
}
return map;
} }
extern "C" void status_t
file_map_delete(void *_map) FileMap::Translate(off_t offset, size_t size, file_io_vec* vecs, size_t* _count)
{ {
file_map *map = (file_map *)_map;
if (map == NULL)
return;
TRACE(("file_map_delete(map = %p)\n", map));
delete map;
}
extern "C" void
file_map_set_size(void *_map, off_t size)
{
if (_map == NULL)
return;
file_map *map = (file_map *)_map;
if (size < map->size)
map->Invalidate(size, map->size - size);
map->size = size;
}
extern "C" void
file_map_invalidate(void *_map, off_t offset, off_t size)
{
if (_map == NULL)
return;
file_map *map = (file_map *)_map;
map->Invalidate(offset, size);
}
extern "C" status_t
file_map_translate(void *_map, off_t offset, size_t size, file_io_vec *vecs,
size_t *_count)
{
if (_map == NULL)
return B_BAD_VALUE;
TRACE(("file_map_translate(map %p, offset %Ld, size %ld)\n",
_map, offset, size));
file_map &map = *(file_map *)_map;
size_t maxVecs = *_count; size_t maxVecs = *_count;
status_t status = B_OK; status_t status = B_OK;
if (offset >= map.size) { if (offset >= Size()) {
*_count = 0; *_count = 0;
return B_OK; return B_OK;
} }
if (offset + size > map.size) if (offset + size > fSize)
size = map.size - offset; size = fSize - offset;
// First, we need to make sure that we have already cached all file // First, we need to make sure that we have already cached all file
// extents needed for this request. // extents needed for this request.
file_extent *lastExtent = NULL; file_extent* lastExtent = NULL;
if (map.count > 0) if (fCount > 0)
lastExtent = map.ExtentAt(map.count - 1); lastExtent = _ExtentAt(fCount - 1);
off_t mapOffset = 0; off_t mapOffset = 0;
if (lastExtent != NULL) if (lastExtent != NULL)
@@ -359,12 +307,11 @@ file_map_translate(void *_map, off_t offset, size_t size, file_io_vec *vecs,
while (mapOffset < end) { while (mapOffset < end) {
// We don't have the requested extents yet, retrieve them // We don't have the requested extents yet, retrieve them
size_t vecCount = maxVecs; size_t vecCount = maxVecs;
status = vfs_get_file_map(map.vnode, mapOffset, ~0UL, vecs, status = vfs_get_file_map(Vnode(), mapOffset, ~0UL, vecs, &vecCount);
&vecCount);
if (status < B_OK && status != B_BUFFER_OVERFLOW) if (status < B_OK && status != B_BUFFER_OVERFLOW)
return status; return status;
status_t addStatus = map.Add(vecs, vecCount, mapOffset); status_t addStatus = _Add(vecs, vecCount, mapOffset);
if (addStatus != B_OK) { if (addStatus != B_OK) {
// only clobber the status in case of failure // only clobber the status in case of failure
status = addStatus; status = addStatus;
@@ -381,13 +328,13 @@ file_map_translate(void *_map, off_t offset, size_t size, file_io_vec *vecs,
// we need to translate it for the requested access. // we need to translate it for the requested access.
uint32 index; uint32 index;
file_extent *fileExtent = map.FindExtent(offset, &index); file_extent* fileExtent = _FindExtent(offset, &index);
offset -= fileExtent->offset; offset -= fileExtent->offset;
vecs[0].offset = fileExtent->disk.offset + offset; vecs[0].offset = fileExtent->disk.offset + offset;
vecs[0].length = fileExtent->disk.length - offset; vecs[0].length = fileExtent->disk.length - offset;
if (vecs[0].length >= size || index >= map.count - 1) { if (vecs[0].length >= size || index >= fCount - 1) {
*_count = 1; *_count = 1;
return B_OK; return B_OK;
} }
@@ -396,7 +343,7 @@ file_map_translate(void *_map, off_t offset, size_t size, file_io_vec *vecs,
size -= vecs[0].length; size -= vecs[0].length;
for (index = 1; index < map.count;) { for (index = 1; index < fCount;) {
fileExtent++; fileExtent++;
vecs[index] = fileExtent->disk; vecs[index] = fileExtent->disk;
@@ -417,3 +364,71 @@ file_map_translate(void *_map, off_t offset, size_t size, file_io_vec *vecs,
return B_OK; return B_OK;
} }
// #pragma mark - public FS API
extern "C" void*
file_map_create(dev_t mountID, ino_t vnodeID, off_t size)
{
TRACE(("file_map_create(mountID = %ld, vnodeID = %Ld, size = %Ld)\n",
mountID, vnodeID, size));
// Get the vnode for the object
// (note, this does not grab a reference to the node)
struct vnode* vnode;
if (vfs_lookup_vnode(mountID, vnodeID, &vnode) != B_OK)
return NULL;
return new(std::nothrow) FileMap(vnode, size);
}
extern "C" void
file_map_delete(void* _map)
{
FileMap* map = (FileMap*)_map;
if (map == NULL)
return;
TRACE(("file_map_delete(map = %p)\n", map));
delete map;
}
extern "C" void
file_map_set_size(void* _map, off_t size)
{
FileMap* map = (FileMap*)_map;
if (map == NULL)
return;
map->SetSize(size);
}
extern "C" void
file_map_invalidate(void* _map, off_t offset, off_t size)
{
FileMap* map = (FileMap*)_map;
if (map == NULL)
return;
map->Invalidate(offset, size);
}
extern "C" status_t
file_map_translate(void* _map, off_t offset, size_t size, file_io_vec* vecs,
size_t* _count)
{
TRACE(("file_map_translate(map %p, offset %Ld, size %ld)\n",
_map, offset, size));
FileMap* map = (FileMap*)_map;
if (map == NULL)
return B_BAD_VALUE;
return map->Translate(offset, size, vecs, _count);
}