@@ -5,8 +5,7 @@ use std::path::Path;
5
5
use hdf5_sys:: h5f:: {
6
6
H5Fclose , H5Fcreate , H5Fflush , H5Fget_access_plist , H5Fget_create_plist , H5Fget_filesize ,
7
7
H5Fget_freespace , H5Fget_intent , H5Fget_obj_count , H5Fget_obj_ids , H5Fopen , H5F_ACC_DEFAULT ,
8
- H5F_ACC_EXCL , H5F_ACC_RDONLY , H5F_ACC_RDWR , H5F_ACC_TRUNC , H5F_OBJ_ALL , H5F_OBJ_FILE ,
9
- H5F_SCOPE_LOCAL ,
8
+ H5F_ACC_EXCL , H5F_ACC_RDONLY , H5F_ACC_RDWR , H5F_ACC_TRUNC , H5F_SCOPE_LOCAL ,
10
9
} ;
11
10
12
11
use crate :: hl:: plist:: {
@@ -133,6 +132,7 @@ impl File {
133
132
}
134
133
135
134
/// Returns objects IDs of the contained objects. NOTE: these are borrowed references.
135
+ #[ allow( unused) ]
136
136
fn get_obj_ids ( & self , types : c_uint ) -> Vec < hid_t > {
137
137
h5lock ! ( {
138
138
let count = h5call!( H5Fget_obj_count ( self . id( ) , types) ) . unwrap_or( 0 ) as size_t;
@@ -151,26 +151,11 @@ impl File {
151
151
}
152
152
153
153
/// Closes the file and invalidates all open handles for contained objects.
154
- pub fn close ( self ) {
155
- h5lock ! ( {
156
- let file_ids = self . get_obj_ids( H5F_OBJ_FILE ) ;
157
- let object_ids = self . get_obj_ids( H5F_OBJ_ALL & !H5F_OBJ_FILE ) ;
158
- for file_id in & file_ids {
159
- if let Ok ( handle) = Handle :: try_new( * file_id) {
160
- handle. decref_full( ) ;
161
- }
162
- }
163
- for object_id in & object_ids {
164
- if let Ok ( handle) = Handle :: try_new( * object_id) {
165
- handle. decref_full( ) ;
166
- }
167
- }
168
- H5Fclose ( self . id( ) ) ;
169
- while self . is_valid( ) {
170
- self . 0 . decref( ) ;
171
- }
172
- self . 0 . decref( ) ;
173
- } ) ;
154
+ pub fn close ( self ) -> Result < ( ) > {
155
+ let id = self . id ( ) ;
156
+ // Ensure we only decref once
157
+ std:: mem:: forget ( self . 0 ) ;
158
+ h5call ! ( H5Fclose ( id) ) . map ( |_| ( ) )
174
159
}
175
160
176
161
/// Returns a copy of the file access property list.
@@ -500,29 +485,86 @@ pub mod tests {
500
485
}
501
486
502
487
#[ test]
503
- pub fn test_close_automatic ( ) {
504
- // File going out of scope should just close its own handle
488
+ fn test_strong_close ( ) {
489
+ use crate :: hl :: plist :: file_access :: FileCloseDegree ;
505
490
with_tmp_path ( |path| {
506
- let file = File :: create ( & path) . unwrap ( ) ;
491
+ let file = File :: with_options ( )
492
+ . with_fapl ( |fapl| fapl. fclose_degree ( FileCloseDegree :: Strong ) )
493
+ . create ( & path)
494
+ . unwrap ( ) ;
495
+ assert_eq ! ( file. refcount( ) , 1 ) ;
496
+ let fileid = file. id ( ) ;
497
+
507
498
let group = file. create_group ( "foo" ) . unwrap ( ) ;
499
+ assert_eq ! ( file. refcount( ) , 1 ) ;
500
+ assert_eq ! ( group. refcount( ) , 1 ) ;
501
+
508
502
let file_copy = group. file ( ) . unwrap ( ) ;
503
+ assert_eq ! ( group. refcount( ) , 1 ) ;
504
+ assert_eq ! ( file. refcount( ) , 2 ) ;
505
+ assert_eq ! ( file_copy. refcount( ) , 2 ) ;
506
+
509
507
drop ( file) ;
510
- assert ! ( group. is_valid( ) ) ;
511
- assert ! ( file_copy. is_valid( ) ) ;
508
+ assert_eq ! ( crate :: handle:: refcount( fileid) . unwrap( ) , 1 ) ;
509
+ assert_eq ! ( group. refcount( ) , 1 ) ;
510
+ assert_eq ! ( file_copy. refcount( ) , 1 ) ;
511
+
512
+ h5lock ! ( {
513
+ // Lock to ensure fileid does not get overwritten
514
+ let groupid = group. id( ) ;
515
+ drop( file_copy) ;
516
+ assert!( crate :: handle:: refcount( fileid) . is_err( ) ) ;
517
+ assert!( crate :: handle:: refcount( groupid) . is_err( ) ) ;
518
+ assert!( !group. is_valid( ) ) ;
519
+ } ) ;
512
520
} ) ;
513
521
}
514
522
515
523
#[ test]
516
- pub fn test_close_manual ( ) {
517
- // File::close() should close handles of all related objects
524
+ fn test_weak_close ( ) {
525
+ use crate :: hl:: plist:: file_access:: FileCloseDegree ;
526
+ with_tmp_path ( |path| {
527
+ let file = File :: with_options ( )
528
+ . with_fapl ( |fapl| fapl. fclose_degree ( FileCloseDegree :: Weak ) )
529
+ . create ( & path)
530
+ . unwrap ( ) ;
531
+ assert_eq ! ( file. refcount( ) , 1 ) ;
532
+ let fileid = file. id ( ) ;
533
+
534
+ let group = file. create_group ( "foo" ) . unwrap ( ) ;
535
+ assert_eq ! ( file. refcount( ) , 1 ) ;
536
+ assert_eq ! ( group. refcount( ) , 1 ) ;
537
+
538
+ let file_copy = group. file ( ) . unwrap ( ) ;
539
+ assert_eq ! ( group. refcount( ) , 1 ) ;
540
+ assert_eq ! ( file. refcount( ) , 2 ) ;
541
+ assert_eq ! ( file_copy. refcount( ) , 2 ) ;
542
+
543
+ drop ( file) ;
544
+ assert_eq ! ( crate :: handle:: refcount( fileid) . unwrap( ) , 1 ) ;
545
+ assert_eq ! ( group. refcount( ) , 1 ) ;
546
+ assert_eq ! ( file_copy. refcount( ) , 1 ) ;
547
+
548
+ h5lock ! ( {
549
+ // Lock to ensure fileid does not get overwritten
550
+ drop( file_copy) ;
551
+ assert!( crate :: handle:: refcount( fileid) . is_err( ) ) ;
552
+ } ) ;
553
+ assert_eq ! ( group. refcount( ) , 1 ) ;
554
+ } ) ;
555
+ }
556
+
557
+ #[ test]
558
+ pub fn test_close_automatic ( ) {
559
+ // File going out of scope should just close its own handle
518
560
with_tmp_path ( |path| {
519
561
let file = File :: create ( & path) . unwrap ( ) ;
520
562
let group = file. create_group ( "foo" ) . unwrap ( ) ;
521
563
let file_copy = group. file ( ) . unwrap ( ) ;
522
- file . close ( ) ;
523
- assert ! ( ! group. is_valid( ) ) ;
524
- assert ! ( ! file_copy. is_valid( ) ) ;
525
- } )
564
+ drop ( file ) ;
565
+ assert ! ( group. is_valid( ) ) ;
566
+ assert ! ( file_copy. is_valid( ) ) ;
567
+ } ) ;
526
568
}
527
569
528
570
#[ test]
@@ -532,7 +574,7 @@ pub mod tests {
532
574
FileBuilder :: new ( ) . with_fapl ( |p| p. core_filebacked ( false ) ) . create ( & path) . unwrap ( ) ;
533
575
file. create_group ( "x" ) . unwrap ( ) ;
534
576
assert ! ( file. is_valid( ) ) ;
535
- file. close ( ) ;
577
+ file. close ( ) . unwrap ( ) ;
536
578
assert ! ( fs:: metadata( & path) . is_err( ) ) ;
537
579
assert_err ! (
538
580
FileBuilder :: new( ) . with_fapl( |p| p. core( ) ) . open( & path) ,
@@ -548,7 +590,7 @@ pub mod tests {
548
590
FileBuilder :: new ( ) . with_fapl ( |p| p. core_filebacked ( true ) ) . create ( & path) . unwrap ( ) ;
549
591
assert ! ( file. is_valid( ) ) ;
550
592
file. create_group ( "bar" ) . unwrap ( ) ;
551
- file. close ( ) ;
593
+ file. close ( ) . unwrap ( ) ;
552
594
assert ! ( fs:: metadata( & path) . is_ok( ) ) ;
553
595
File :: open ( & path) . unwrap ( ) . group ( "bar" ) . unwrap ( ) ;
554
596
} )
@@ -594,8 +636,8 @@ pub mod tests {
594
636
let path = dir. join ( "qwe.h5" ) ;
595
637
let file = File :: create ( & path) . unwrap ( ) ;
596
638
assert_eq ! ( format!( "{:?}" , file) , "<HDF5 file: \" qwe.h5\" (read/write)>" ) ;
597
- let root = file. file ( ) . unwrap ( ) ;
598
- file . close ( ) ;
639
+ file. close ( ) . unwrap ( ) ;
640
+ let root = File :: from_handle ( Handle :: invalid ( ) ) ;
599
641
assert_eq ! ( format!( "{:?}" , root) , "<HDF5 file: invalid id>" ) ;
600
642
let file = File :: open ( & path) . unwrap ( ) ;
601
643
assert_eq ! ( format!( "{:?}" , file) , "<HDF5 file: \" qwe.h5\" (read-only)>" ) ;
0 commit comments