@@ -945,6 +945,7 @@
Loading
945 945
pub fn exp_from_content_size(size: u64) -> u8 {
946 946
    // content + size + match_pointer:page+ match_pointer:pos  + page_header
947 947
    let final_size = size + u64::from(PAGE_METADATA_SIZE);
948 +
    let final_size = u64::max(final_size, 32);
948 949
    // Should be there a better way, so far is OK.
949 950
    let mut res: u8 = 1;
950 951
    loop {

@@ -6,15 +6,13 @@
Loading
6 6
    cmp,
7 7
    fs::File,
8 8
    io::{self, Cursor, Read, Seek, SeekFrom, Write},
9 -
    sync::{
10 -
        atomic::{AtomicU64, Ordering},
11 -
        Arc, Mutex,
12 -
    },
9 +
    sync::{Arc, Mutex},
13 10
};
14 -
pub const PAGE_METADATA_SIZE: u32 = 2;
11 +
pub const PAGE_METADATA_SIZE: u32 = 3;
15 12
16 13
pub trait UpdateList {
17 14
    fn update(&mut self, exp: u8, page: u64) -> PRes<u64>;
15 +
    fn remove(&mut self, exp: u8, page: u64, next: u64) -> PRes<()>;
18 16
}
19 17
20 18
pub trait Device: Sync + Send {
@@ -82,14 +80,14 @@
Loading
82 80
83 81
    pub fn slice(&self, len: usize) -> &[u8] {
84 82
        let final_len = self.pos + len;
85 -
        debug_assert!(final_len < self.buff.len());
83 +
        debug_assert!(final_len < self.buff.len() - 1);
86 84
        &self.buff[self.pos..final_len]
87 85
    }
88 86
}
89 87
90 88
impl Read for ReadPage {
91 89
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
92 -
        let len = self.buff.len();
90 +
        let len = self.buff.len() - 1;
93 91
        let amt = cmp::min(self.pos, len);
94 92
        let read = Read::read(&mut &self.buff[(amt as usize)..len], buf)?;
95 93
        self.pos += read;
@@ -173,7 +171,7 @@
Loading
173 171
174 172
impl Read for Page {
175 173
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
176 -
        let len = self.buff.len();
174 +
        let len = self.buff.len() - 1;
177 175
        let amt = cmp::min(self.pos, len);
178 176
        let read = Read::read(&mut &self.buff[(amt as usize)..len], buf)?;
179 177
        self.pos += read;
@@ -190,7 +188,7 @@
Loading
190 188
impl Write for Page {
191 189
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
192 190
        let pre = self.pos;
193 -
        let len = self.buff.len();
191 +
        let len = self.buff.len() - 1;
194 192
        if pre + (*buf).len() > len {
195 193
            panic!(
196 194
                "Over page allowed content size:{}, data size: {}",
@@ -316,6 +314,7 @@
Loading
316 314
    let size: u64 = (1 << exp) as u64; //EXP - (size_exp+size_mitigator);
317 315
    let mut ve = vec![0 as u8; size as usize];
318 316
    ve[0] = exp;
317 +
    ve[size as usize - 1] = exp;
319 318
    let offset = fl.seek(SeekFrom::End(0))?;
320 319
    fl.write_all(&ve)?; //exp
321 320
    Ok(Page::new(ve, 2, offset, exp))
@@ -342,7 +341,8 @@
Loading
342 341
    let exp = fl.read_u8()?;
343 342
    let size = (1 << exp) as u64; //EXP - (size_exp+size_mitigator);
344 343
    if page + size == fl.len()? {
345 -
        fl.set_len(page + 1)?;
344 +
        fl.set_len(page)?;
345 +
        while check_and_trim(fl, update_list)? {}
346 346
    } else {
347 347
        let old = update_list.update(exp, page)?;
348 348
        fl.seek(SeekFrom::Start(page + 1))?;
@@ -357,14 +357,59 @@
Loading
357 357
        if exp >= 5 {
358 358
            fl.write_all(&[0u8; 16])?;
359 359
        }
360 +
361 +
        let mut data = [0; 8];
362 +
        write_u64(&mut data, page);
363 +
        fl.seek(SeekFrom::Start(old + 9))?;
364 +
        fl.write_all(&data)?;
360 365
    }
361 366
    Ok(())
362 367
}
363 368
369 +
fn check_and_trim<T: Write + Read + Seek + SizeTool>(fl: &mut T, update_list: &mut dyn UpdateList) -> PRes<bool> {
370 +
    let len = fl.seek(SeekFrom::End(0))?;
371 +
    if len == 0 {
372 +
        return Ok(false);
373 +
    }
374 +
375 +
    fl.seek(SeekFrom::Start(len - 1))?;
376 +
    let exp = fl.read_u8()?;
377 +
    if exp == 0 {
378 +
        return Ok(false);
379 +
    }
380 +
    let size = (1 << exp) as u64; //EXP - (size_exp+size_mitigator);
381 +
    let mut header = [0u8; 18];
382 +
    let page = len - size;
383 +
    if page == 0 {
384 +
        return Ok(false);
385 +
    }
386 +
    fl.seek(SeekFrom::Start(page + 1))?;
387 +
    fl.read_exact(&mut header)?;
388 +
    if is_free(header[0]) {
389 +
        let next = read_u64(&header[2..10]);
390 +
        let prev = read_u64(&header[10..18]);
391 +
        if prev == 0 {
392 +
            update_list.remove(exp, page, next)?;
393 +
        } else {
394 +
            let mut data = [8u8];
395 +
            write_u64(&mut data, next);
396 +
            fl.seek(SeekFrom::Start(prev + 10))?;
397 +
            fl.write_all(&data)?;
398 +
            write_u64(&mut data, prev);
399 +
            fl.seek(SeekFrom::Start(next + 2))?;
400 +
            fl.write_all(&data)?;
401 +
        }
402 +
        fl.set_len(page)?;
403 +
        Ok(true)
404 +
    } else {
405 +
        Ok(false)
406 +
    }
407 +
}
408 +
364 409
#[cfg(unix)]
365 410
pub struct DiscRef {
366 411
    file: File,
367 -
    size: AtomicU64,
412 +
    size: Mutex<u64>,
368 413
}
369 414
370 415
#[cfg(unix)]
@@ -373,28 +418,61 @@
Loading
373 418
        let len = file.len()?;
374 419
        Ok(DiscRef {
375 420
            file,
376 -
            size: AtomicU64::new(len),
421 +
            size: Mutex::new(len),
377 422
        })
378 423
    }
379 424
380 -
    fn create_page_offset(&self, size: u64) -> u64 {
381 -
        loop {
382 -
            let current_size = self.size.load(Ordering::Acquire);
383 -
            let new_size = current_size + size;
384 -
            if self.size.compare_and_swap(current_size, new_size, Ordering::SeqCst) == current_size {
385 -
                break current_size;
386 -
            }
387 -
        }
425 +
    fn create_page_offset(&self, size: u64) -> PRes<u64> {
426 +
        let mut current = self.size.lock()?;
427 +
        let page = *current;
428 +
        *current += size;
429 +
        return Ok(page);
388 430
    }
389 431
    fn trim_if_possible(&self, page: u64, size: u64) -> PRes<bool> {
390 -
        let current_size = self.size.load(Ordering::Acquire);
391 -
        if page + size == current_size {
392 -
            if self.size.compare_and_swap(current_size, page + 1, Ordering::SeqCst) == current_size {
393 -
                self.file.set_len(page + 1)?;
394 -
                Ok(true)
432 +
        let mut current = self.size.lock()?;
433 +
        if page + size == *current {
434 +
            *current = page;
435 +
            self.file.set_len(page)?;
436 +
            Ok(true)
437 +
        } else {
438 +
            Ok(false)
439 +
        }
440 +
    }
441 +
442 +
    fn check_and_trim(&self, update_list: &mut dyn UpdateList) -> PRes<bool> {
443 +
        use std::os::unix::prelude::FileExt;
444 +
        let mut lock = self.size.lock()?;
445 +
        let value = *lock;
446 +
        if value == 0 {
447 +
            return Ok(false);
448 +
        }
449 +
        let mut exp = [0u8];
450 +
        self.file.read_exact_at(&mut exp, value - 1)?;
451 +
        if exp[0] == 0 {
452 +
            return Ok(false);
453 +
        }
454 +
        let size = (1 << exp[0]) as u64; //EXP - (size_exp+size_mitigator);
455 +
        let mut header = [0u8; 18];
456 +
        let page = value - size;
457 +
        if page == 0 {
458 +
            return Ok(false);
459 +
        }
460 +
        self.file.read_exact_at(&mut header, page + 1)?;
461 +
        if is_free(header[0]) {
462 +
            let next = read_u64(&header[2..10]);
463 +
            let prev = read_u64(&header[10..18]);
464 +
            if prev == 0 {
465 +
                update_list.remove(exp[0], page, next)?;
395 466
            } else {
396 -
                Ok(false)
467 +
                let mut data = [8u8];
468 +
                write_u64(&mut data, next);
469 +
                self.file.write_all_at(&data, prev + 10)?;
470 +
                write_u64(&mut data, prev);
471 +
                self.file.write_all_at(&data, next + 2)?;
397 472
            }
473 +
            *lock = page;
474 +
            self.file.set_len(page)?;
475 +
            Ok(true)
398 476
        } else {
399 477
            Ok(false)
400 478
        }
@@ -430,17 +508,22 @@
Loading
430 508
    }
431 509
432 510
    fn create_page_raw(&self, exp: u8) -> PRes<u64> {
511 +
        use std::os::unix::prelude::FileExt;
433 512
        let size: u64 = (1 << exp) as u64; //EXP - (size_exp+size_mitigator);
434 -
        let offset = self.create_page_offset(size);
513 +
        let offset = self.create_page_offset(size)?;
514 +
        let mut ve = [0u8];
515 +
        ve[0] = exp;
516 +
        self.file.write_all_at(&ve, offset + size - 1)?; //exp
435 517
        Ok(offset)
436 518
    }
437 519
438 520
    fn create_page(&self, exp: u8) -> PRes<Page> {
439 521
        use std::os::unix::prelude::FileExt;
440 522
        let size: u64 = (1 << exp) as u64; //EXP - (size_exp+size_mitigator);
441 -
        let offset = self.create_page_offset(size);
523 +
        let offset = self.create_page_offset(size)?;
442 524
        let mut ve = vec![0 as u8; size as usize];
443 525
        ve[0] = exp;
526 +
        ve[size as usize - 1] = exp;
444 527
        self.file.write_all_at(&ve, offset)?; //exp
445 528
        Ok(Page::new(ve, 2, offset, exp))
446 529
    }
@@ -480,6 +563,8 @@
Loading
480 563
            if exp[0] >= 5 {
481 564
                self.file.write_all_at(&[0u8; 16], page + 10)?;
482 565
            }
566 +
        } else {
567 +
            while self.check_and_trim(update_list)? {}
483 568
        }
484 569
        Ok(())
485 570
    }
@@ -668,6 +753,9 @@
Loading
668 753
        fn update(&mut self, _: u8, _: u64) -> PRes<u64> {
669 754
            panic!("should not put the free in the free list")
670 755
        }
756 +
        fn remove(&mut self, _: u8, _: u64, _: u64) -> PRes<()> {
757 +
            panic!("should not put the free in the free list")
758 +
        }
671 759
    }
672 760
673 761
    fn create_load_trim_device(device: &mut dyn Device) {
@@ -678,11 +766,27 @@
Loading
678 766
        assert!(device.load_page(page).is_err());
679 767
    }
680 768
769 +
    fn create_load_two_trim_device(device: &mut dyn Device) {
770 +
        let _not_free = device.create_page(5).unwrap().get_index();
771 +
        let page = device.create_page(5).unwrap().get_index();
772 +
        let pg = &mut device.load_page(page).unwrap().clone_write();
773 +
        device.flush_page(pg).unwrap();
774 +
        let page_1 = device.create_page(5).unwrap().get_index();
775 +
        let pg = &mut device.load_page(page_1).unwrap().clone_write();
776 +
        device.flush_page(pg).unwrap();
777 +
        device.trim_or_free_page(page, &mut IgnoreCase {}).unwrap();
778 +
        device.trim_or_free_page(page_1, &mut IgnoreCase {}).unwrap();
779 +
        assert!(device.load_page(page).is_err());
780 +
    }
781 +
681 782
    struct IgnoreCase {}
682 783
    impl UpdateList for IgnoreCase {
683 784
        fn update(&mut self, _: u8, _: u64) -> PRes<u64> {
684 785
            Ok(0)
685 786
        }
787 +
        fn remove(&mut self, _: u8, _: u64, _: u64) -> PRes<()> {
788 +
            Ok(())
789 +
        }
686 790
    }
687 791
688 792
    fn create_not_trim_not_last_device(device: &mut dyn Device) {
@@ -743,6 +847,15 @@
Loading
743 847
        create_load_trim_device(&mut MemRef::new().unwrap());
744 848
    }
745 849
850 +
    #[test]
851 +
    fn create_two_load_trim_disc() {
852 +
        create_load_two_trim_device(&mut temp_disc_ref("disc_ref_two_trim.raw"));
853 +
    }
854 +
    #[test]
855 +
    fn create_two_load_trim_memory() {
856 +
        create_load_two_trim_device(&mut MemRef::new().unwrap());
857 +
    }
858 +
746 859
    #[test]
747 860
    fn create_not_trim_not_last_disc() {
748 861
        create_not_trim_not_last_device(&mut temp_disc_ref("disc_ref_no_trim.raw"));

@@ -272,6 +272,18 @@
Loading
272 272
        debug_assert!(old != page, "freeing: {} already free: {} ", page, old);
273 273
        Ok(old)
274 274
    }
275 +
276 +
    fn remove(&mut self, size: u8, page: u64, next: u64) -> PRes<()> {
277 +
        let old = self[size as usize];
278 +
        self[size as usize] = next;
279 +
        debug_assert!(
280 +
            old == page,
281 +
            "trimmed page not in top list expected:{} current:{} ",
282 +
            page,
283 +
            old
284 +
        );
285 +
        Ok(())
286 +
    }
275 287
}
276 288
277 289
#[cfg(test)]
Files Coverage
src 92.79%
tests 98.56%
Project Totals (29 files) 93.83%
1
coverage:
2
  status:
3
    project:
4
      default:
5
        target: 80%
6
        threshold: 1.0%
7
    patch: off
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading