diff --git a/NEWS.md b/NEWS.md index 3884e5bca56712..ca413c616f6ece 100644 --- a/NEWS.md +++ b/NEWS.md @@ -228,6 +228,7 @@ They are still available on rubygems.org and can be installed with * irb 1.18.0 * 1.16.0 to [v1.17.0][irb-v1.17.0], [v1.18.0][irb-v1.18.0] * reline 0.7.0 + * 0.6.3 to [v0.7.0][reline-v0.7.0] ### RubyGems and Bundler @@ -464,3 +465,4 @@ A lot of work has gone into making Ractors more stable, performant, and usable. [win32ole-v1.9.3]: https://github.com/ruby/win32ole/releases/tag/v1.9.3 [irb-v1.17.0]: https://github.com/ruby/irb/releases/tag/v1.17.0 [irb-v1.18.0]: https://github.com/ruby/irb/releases/tag/v1.18.0 +[reline-v0.7.0]: https://github.com/ruby/reline/releases/tag/v0.7.0 diff --git a/doc/file/timestamps.md b/doc/file/timestamps.md index 24f63452d13a3f..0f8ec96c70a4a2 100644 --- a/doc/file/timestamps.md +++ b/doc/file/timestamps.md @@ -1,23 +1,56 @@ # \Filesystem Timestamps A filesystem entry (the name of a file or directory) -has several times (called timestamps) associated with it. +has several associated times, called timestamps. A Ruby method that returns a filesystem timestamp (as a Time object) is actually returning "whatever the filesystem says"; the returned times may vary among filesystems, even on the same machine. -These timestamps methods are: +Each of these methods returns a Time object: + +| Name | Meaning | Changes | +|:--------------------------------:|----------------------------------------|---------------------------------------| +| [`birthtime`](#birth-time) | Create time. | Never. | +| [`mtime`](#modification-time) | Modification time. | When written; see Note 1. | +| [`atime`](#access-time) | Access time. | When read; see Note 2. | +| [`ctime`](#metadata-change-time) | Metadata-change time (or create time). | See [`ctime`](#metadata-change-time). | + +Notes: + +1. Modification time update may be delayed by the filesystem. +2. Access time may occur immediately, later, or never, depending on filesystem settings. + +Each of these methods updates the access time and modification time for an entry: + +- File::utime, Pathname#utime: follow symbolic links. +- File::lutime, Pathname#lutime: do not follow symbolic links. + +## \File Timestamps + +| Operation | Affects
birthtime | Affects
ctime | Affects
mtime | Affects
atime | +|:------------------:|:---------------------:|:----------------:|:----------------:|:--------------------------:| +| Create | **Yes** | **Yes** | **Yes** | **Yes** | +| Write content | No | No | **Yes** | No | +| Read content | No | No | No | *Filesystem-
dependent* | +| Rename/Move | No | **Yes** | No | No | +| Change permissions | No | **Yes** | No | No | +| Change ownership | No | **Yes** | No | No | + + +## Directory Timestamps + +| Operation | Affects
birthtime | Affects
ctime | Affects
mtime | Affects
atime | +|:------------------:|:--------------------:|:----------------:|:----------------:|:--------------------------:| +| Create | **Yes** | **Yes** | **Yes** | **Yes** | +| Write entries | No | No | **Yes** | No | +| Read entries | No | No | No | *Filesystem-
dependent* | +| Rename/Move | No | **Yes** | No | No | +| Change permissions | No | **Yes** | No | No | +| Change ownership | No | **Yes** | No | No | + -| Name | Meaning | Changes | -|:--------------------------------:|----------------------------------------|---------------| -| [`birthtime`](#birth-time) | Create time. | Never. | -| [`mtime`](#modification-time) | Modification time. | When written. | -| [`atime`](#access-time) | Access time. | When read. | -| [`ctime`](#metadata-change-time) | Metadata-change time (or create time). | See below. | -A method raises an exception if the filesystem does not support -the corresponding timestamp. ## Birth \Time @@ -64,6 +97,15 @@ The modification time (along with the access time) may also be updated explicitl The access time for an entry is the time of the most recent read for the entry, as reported by the underlying filesystem. +Depending on a filesystem's settings, reading an entry may cause the access time +to be updated immediately, later, or never. + +The access time for a file is commonly the most recent time the file was read, +or if never read, the time it was created. + +The access time for a directory is commonly the most recent time its entries were read, +or if never read, the time it was created. + Each of these methods returns the access time for an entry as a Time object: - File::atime. @@ -78,41 +120,6 @@ The access time (along with the modification time) may also be updated explicitl - Pathname#lutime. - Pathname#utime. -Depending on a filesystem's settings, reading an entry may cause the access time -to be updated immediately, later, or never; -thus in the tables below, some entries say "Filesystem-dependent." - -### File - -The access time for a file is commonly the most recent time the file was read, -or if never read, the time it was created: - -| Operation | Updates Access \Time | -|:------------------:|:--------------------:| -| Create | Yes | -| Read | Filesystem-dependent | -| Write | No | -| Rename | No | -| Move | No | -| Change permissions | No | -| Change ownership | No | - - -### Directory - -The access time for a directory is commonly the most recent time its entries were read, -or if never read, the time it was created: - -| Operation | Updates Access \Time | -|:------------------:|:--------------------:| -| Create | Yes | -| Read entries | Filesystem-dependent | -| Write entries | No | -| Rename | No | -| Move | No | -| Change permissions | No | -| Change ownership | No | - ## Metadata-Change \Time The metadata-change time for an entry is the time the entry last read. diff --git a/hash.c b/hash.c index 6d61079cc9ab71..dd57c10edb4059 100644 --- a/hash.c +++ b/hash.c @@ -1482,24 +1482,35 @@ compact_after_delete(VALUE hash) } static inline size_t -hash_slot_size(bool st) +hash_slot_size(size_t capa, bool frozen) { - return sizeof(struct RHash) + (st ? sizeof(st_table) : sizeof(ar_table)); + if (capa > RHASH_AR_TABLE_MAX_SIZE) { + return sizeof(struct RHash) + sizeof(st_table); + } + + // If the hash is immutable, we can allocate a slot with exactly as much space as needed. + if (frozen) { + return sizeof(struct RHash) + offsetof(ar_table, pairs) + capa * sizeof(ar_table_pair); + } + + return sizeof(struct RHash) + sizeof(ar_table); } static VALUE -hash_alloc_flags(VALUE klass, VALUE flags, VALUE ifnone, bool st) +hash_alloc_capa(VALUE klass, VALUE flags, VALUE ifnone, size_t size, bool frozen) { - const size_t size = hash_slot_size(st); - VALUE hash = rb_newobj_of(klass, T_HASH | flags, size); - return rb_hash_set_ifnone(hash, ifnone); + VALUE hash = rb_newobj_of(klass, T_HASH | flags, hash_slot_size(size, frozen)); + rb_hash_set_ifnone(hash, ifnone); + if (size > RHASH_AR_TABLE_MAX_SIZE) { + hash_st_table_init(hash, &objhash, size); + } + return hash; } static VALUE hash_alloc(VALUE klass) { - /* Allocate to be able to fit both st_table and ar_table. */ - return hash_alloc_flags(klass, 0, Qnil, sizeof(st_table) > sizeof(ar_table)); + return hash_alloc_capa(klass, 0, Qnil, 0, false); } #if USE_ZJIT @@ -1507,7 +1518,7 @@ size_t rb_zjit_hash_new_size(VALUE *flags_out) { *flags_out = T_HASH; - return hash_slot_size(sizeof(st_table) > sizeof(ar_table)); + return hash_slot_size(0, false); } #endif @@ -1537,37 +1548,19 @@ copy_compare_by_id(VALUE hash, VALUE basis) VALUE rb_hash_new_with_size(st_index_t size) { - bool st = size > RHASH_AR_TABLE_MAX_SIZE; - VALUE ret = hash_alloc_flags(rb_cHash, 0, Qnil, st); - - if (st) { - hash_st_table_init(ret, &objhash, size); - } - - return ret; + return hash_alloc_capa(rb_cHash, 0, Qnil, size, false); } VALUE rb_hash_new_capa(long capa) { - return rb_hash_new_with_size((st_index_t)capa); + return hash_alloc_capa(rb_cHash, 0, Qnil, capa, false); } VALUE rb_hash_alloc_fixed_size(VALUE klass, st_index_t size) { - VALUE ret; - if (size > RHASH_AR_TABLE_MAX_SIZE) { - ret = hash_alloc_flags(klass, 0, Qnil, true); - hash_st_table_init(ret, &objhash, size); - } - else { - size_t slot_size = sizeof(struct RHash) + offsetof(ar_table, pairs) + size * sizeof(ar_table_pair); - ret = rb_newobj_of(klass, T_HASH, slot_size); - } - - RHASH_SET_IFNONE(ret, Qnil); - return ret; + return hash_alloc_capa(klass, 0, Qnil, size, true); } static VALUE @@ -1583,8 +1576,6 @@ hash_copy(VALUE ret, VALUE hash) } else { st_table *tab = RHASH_ST_TABLE(ret); - st_init_existing_table_with_size(tab, &objhash, RHASH_AR_TABLE_SIZE(hash)); - int bound = RHASH_AR_TABLE_BOUND(hash); for (int i = 0; i < bound; i++) { if (ar_cleared_entry(hash, i)) continue; @@ -1610,7 +1601,7 @@ hash_copy(VALUE ret, VALUE hash) static VALUE hash_dup_with_compare_by_id(VALUE hash) { - VALUE dup = hash_alloc_flags(rb_cHash, 0, Qnil, RHASH_ST_TABLE_P(hash)); + VALUE dup = hash_alloc_capa(rb_cHash, 0, Qnil, RHASH_SIZE(hash), false); if (RHASH_ST_TABLE_P(hash)) { RHASH_SET_ST_FLAG(dup); } @@ -1624,8 +1615,8 @@ hash_dup_with_compare_by_id(VALUE hash) static VALUE hash_dup(VALUE hash, VALUE klass, VALUE flags) { - return hash_copy(hash_alloc_flags(klass, flags, RHASH_IFNONE(hash), !RHASH_EMPTY_P(hash) && RHASH_ST_TABLE_P(hash)), - hash); + VALUE dup = hash_alloc_capa(klass, flags, RHASH_IFNONE(hash), RHASH_SIZE(hash), false); + return hash_copy(dup, hash); } VALUE @@ -1655,7 +1646,7 @@ rb_zjit_hash_dup_can_fastpath(VALUE hash, size_t *alloc_size_out, VALUE *flags_o const unsigned int bound = RHASH_AR_TABLE_BOUND(hash); - *alloc_size_out = hash_slot_size(false); + *alloc_size_out = hash_slot_size(0, false); *flags_out = T_HASH | ((VALUE)RHASH_AR_TABLE_SIZE(hash) << RHASH_AR_TABLE_SIZE_SHIFT) | ((VALUE)bound << RHASH_AR_TABLE_BOUND_SHIFT); @@ -3085,11 +3076,18 @@ rb_hash_replace(VALUE hash, VALUE hash2) if (RHASH_AR_TABLE_P(hash)) { hash_ar_free_and_clear_table(hash); + if (RHASH_SIZE(hash2) > RHASH_AR_TABLE_MAX_SIZE) { + RHASH_SET_ST_FLAG(hash); + } } else { hash_st_free_and_clear_table(hash); } + if (RHASH_ST_TABLE_P(hash)) { + st_init_existing_table_with_size(RHASH_ST_TABLE(hash), &objhash, RHASH_SIZE(hash2)); + } + hash_copy(hash, hash2); return hash;