mirror of
https://github.com/quickwit-oss/tantivy.git
synced 2026-10-25 21:22:40 +00:00
@@ -18,6 +18,9 @@ use std::fs::OpenOptions;
|
||||
use directory::error::{OpenWriteError, FileError, OpenDirectoryError};
|
||||
use std::result;
|
||||
use common::make_io_err;
|
||||
use std::fs;
|
||||
use directory::shared_vec_slice::SharedVecSlice;
|
||||
|
||||
|
||||
/// Directory storing data in files, read via MMap.
|
||||
///
|
||||
@@ -127,8 +130,11 @@ impl Seek for SafeFileWriter {
|
||||
|
||||
impl Directory for MmapDirectory {
|
||||
|
||||
|
||||
|
||||
fn open_read(&self, path: &Path) -> result::Result<ReadOnlySource, FileError> {
|
||||
let full_path = self.resolve_path(path);
|
||||
|
||||
let mut mmap_cache = try!(
|
||||
self.mmap_cache
|
||||
.write()
|
||||
@@ -136,14 +142,14 @@ impl Directory for MmapDirectory {
|
||||
make_io_err(format!("Failed to acquired write lock on mmap cache while reading {:?}", path))
|
||||
})
|
||||
);
|
||||
|
||||
let mmap = match mmap_cache.entry(full_path.clone()) {
|
||||
HashMapEntry::Occupied(e) => {
|
||||
e.get().clone()
|
||||
}
|
||||
HashMapEntry::Vacant(vacant_entry) => {
|
||||
let new_mmap = try!(
|
||||
MmapReadOnly::open_path(full_path.clone())
|
||||
.map_err(|err| {
|
||||
let file = try!(
|
||||
File::open(&full_path).map_err(|err| {
|
||||
if err.kind() == io::ErrorKind::NotFound {
|
||||
FileError::FileDoesNotExist(full_path.clone())
|
||||
}
|
||||
@@ -152,10 +158,17 @@ impl Directory for MmapDirectory {
|
||||
}
|
||||
})
|
||||
);
|
||||
if try!(file.metadata()).len() == 0 {
|
||||
// if the file size is 0, it will not be possible
|
||||
// to mmap the file, so we return an anonymous mmap_cache
|
||||
// instead.
|
||||
return Ok(ReadOnlySource::Anonymous(SharedVecSlice::empty()))
|
||||
}
|
||||
let new_mmap = try!(MmapReadOnly::open(&file));
|
||||
vacant_entry.insert(new_mmap.clone());
|
||||
new_mmap
|
||||
}
|
||||
};
|
||||
};
|
||||
Ok(ReadOnlySource::Mmap(mmap))
|
||||
}
|
||||
|
||||
@@ -166,7 +179,7 @@ impl Directory for MmapDirectory {
|
||||
.write(true)
|
||||
.create_new(true)
|
||||
.open(full_path);
|
||||
|
||||
|
||||
let mut file = try!(
|
||||
open_res.map_err(|err| {
|
||||
if err.kind() == io::ErrorKind::AlreadyExists {
|
||||
@@ -177,7 +190,7 @@ impl Directory for MmapDirectory {
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
// making sure the file is created.
|
||||
try!(file.flush());
|
||||
|
||||
@@ -197,16 +210,13 @@ impl Directory for MmapDirectory {
|
||||
make_io_err(format!("Failed to acquired write lock on mmap cache while deleting {:?}", path))
|
||||
})
|
||||
);
|
||||
match mmap_cache.remove(&full_path) {
|
||||
Some(_) => {
|
||||
// it will be munmapped on drop,
|
||||
// when the last reference is gone.
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
Err(FileError::FileDoesNotExist(PathBuf::from(path)))
|
||||
}
|
||||
}
|
||||
// Removing the entry in the MMap cache.
|
||||
// The munmap will appear on Drop,
|
||||
// when the last reference is gone.
|
||||
mmap_cache.remove(&full_path);
|
||||
try!(fs::remove_file(&full_path));
|
||||
try!(self.sync_directory());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn atomic_write(&mut self, path: &Path, data: &[u8]) -> io::Result<()> {
|
||||
|
||||
+65
-24
@@ -28,6 +28,10 @@ mod tests {
|
||||
use std::path::Path;
|
||||
use std::io::SeekFrom;
|
||||
|
||||
lazy_static! {
|
||||
static ref TEST_PATH: &'static Path = Path::new("some_path_for_test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ram_directory() {
|
||||
let mut ram_directory = RAMDirectory::create();
|
||||
@@ -40,48 +44,85 @@ mod tests {
|
||||
test_directory(&mut mmap_directory);
|
||||
}
|
||||
|
||||
fn test_directory_simple(directory: &mut Directory) {
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn ram_directory_panics_if_flush_forgotten() {
|
||||
let mut ram_directory = RAMDirectory::create();
|
||||
let mut write_file = ram_directory.open_write(*TEST_PATH).unwrap();
|
||||
assert!(write_file.write_all(&[4]).is_ok());
|
||||
}
|
||||
|
||||
fn test_simple(directory: &mut Directory) {
|
||||
{
|
||||
let mut write_file = directory.open_write(Path::new("toto")).unwrap();
|
||||
let mut write_file = directory.open_write(*TEST_PATH).unwrap();
|
||||
write_file.write_all(&[4]).unwrap();
|
||||
write_file.write_all(&[3]).unwrap();
|
||||
write_file.write_all(&[7,3,5]).unwrap();
|
||||
write_file.flush().unwrap();
|
||||
}
|
||||
let read_file = directory.open_read(Path::new("toto")).unwrap();
|
||||
let read_file = directory.open_read(*TEST_PATH).unwrap();
|
||||
let data: &[u8] = &*read_file;
|
||||
assert_eq!(data.len(), 5);
|
||||
assert_eq!(data[0], 4);
|
||||
assert_eq!(data[1], 3);
|
||||
assert_eq!(data[2], 7);
|
||||
assert_eq!(data[3], 3);
|
||||
assert_eq!(data[4], 5);
|
||||
assert_eq!(data, &[4u8, 3u8, 7u8, 3u8, 5u8]);
|
||||
assert!(directory.delete(*TEST_PATH).is_ok());
|
||||
}
|
||||
|
||||
|
||||
fn test_directory_seek(directory: &mut Directory) {
|
||||
fn test_seek(directory: &mut Directory) {
|
||||
{
|
||||
let mut write_file = directory.open_write(Path::new("toto_seek")).unwrap();
|
||||
write_file.write_all(&[4]).unwrap();
|
||||
write_file.write_all(&[3]).unwrap();
|
||||
write_file.write_all(&[7,3,5]).unwrap();
|
||||
let mut write_file = directory.open_write(*TEST_PATH).unwrap();
|
||||
write_file.write_all(&[4, 3, 7,3,5]).unwrap();
|
||||
write_file.seek(SeekFrom::Start(0)).unwrap();
|
||||
write_file.write_all(&[3,1]).unwrap();
|
||||
write_file.flush().unwrap();
|
||||
}
|
||||
let read_file = directory.open_read(Path::new("toto_seek")).unwrap();
|
||||
let read_file = directory.open_read(*TEST_PATH).unwrap();
|
||||
let data: &[u8] = &*read_file;
|
||||
assert_eq!(data.len(), 5);
|
||||
assert_eq!(data[0], 3);
|
||||
assert_eq!(data[1], 1);
|
||||
assert_eq!(data[2], 7);
|
||||
assert_eq!(data[3], 3);
|
||||
assert_eq!(data[4], 5);
|
||||
assert_eq!(data, &[3u8, 1u8, 7u8, 3u8, 5u8]);
|
||||
assert!(directory.delete(*TEST_PATH).is_ok());
|
||||
}
|
||||
|
||||
fn test_rewrite_forbidden(directory: &mut Directory) {
|
||||
{
|
||||
directory.open_write(*TEST_PATH).unwrap();
|
||||
}
|
||||
{
|
||||
assert!(directory.open_write(*TEST_PATH).is_err());
|
||||
}
|
||||
assert!(directory.delete(*TEST_PATH).is_ok());
|
||||
}
|
||||
|
||||
fn test_write_create_the_file(directory: &mut Directory) {
|
||||
{
|
||||
assert!(directory.open_read(*TEST_PATH).is_err());
|
||||
let _w = directory.open_write(*TEST_PATH).unwrap();
|
||||
if let Err(e) = directory.open_read(*TEST_PATH) {
|
||||
println!("{:?}", e);
|
||||
}
|
||||
assert!(directory.open_read(*TEST_PATH).is_ok());
|
||||
assert!(directory.delete(*TEST_PATH).is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
fn test_delete(directory: &mut Directory) {
|
||||
assert!(directory.open_read(*TEST_PATH).is_err());
|
||||
let mut write_file = directory.open_write(*TEST_PATH).unwrap();
|
||||
write_file.write_all(&[1, 2, 3, 4]).unwrap();
|
||||
write_file.flush().unwrap();
|
||||
let read_handle = directory.open_read(*TEST_PATH).unwrap();
|
||||
{
|
||||
assert_eq!(&*read_handle, &[1u8, 2u8, 3u8, 4u8]);
|
||||
assert!(directory.delete(*TEST_PATH).is_ok());
|
||||
assert!(directory.delete(Path::new("SomeOtherPath")).is_err());
|
||||
assert_eq!(&*read_handle, &[1u8, 2u8, 3u8, 4u8]);
|
||||
}
|
||||
assert!(directory.open_read(*TEST_PATH).is_err());
|
||||
}
|
||||
|
||||
fn test_directory(directory: &mut Directory) {
|
||||
test_directory_simple(directory);
|
||||
test_directory_seek(directory);
|
||||
test_simple(directory);
|
||||
test_seek(directory);
|
||||
test_rewrite_forbidden(directory);
|
||||
test_write_create_the_file(directory);
|
||||
test_delete(directory);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ impl VecWriter {
|
||||
path: path_buf,
|
||||
data: Cursor::new(Vec::new()),
|
||||
shared_directory: shared_directory,
|
||||
is_flushed: false,
|
||||
is_flushed: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user