view release on metacpan or search on metacpan
5.26.1 2026-09-28
- [32-BIT PERL / CPAN TESTERS QUAD PACKING COMPATIBILITY]
* Implemented transparent cross-platform 64-bit integer packing in AmberDB::Base::Encoder (_pack_ids, _unpack_ids, _pack_single_id).
* Utilizes native 64-bit pack("(Q>)*") / unpack("(Q>)*") on 64-bit Perls with zero performance overhead.
* Automatically falls back to dual 32-bit unsigned network integer pack("(NN)*") / unpack("(NN)*") on 32-bit Perls without quad support (use64bitint=undef, e.g. Raspberry Pi armv6l).
* Guaranteed 100% byte-exact binary compatibility on physical .inx, .fld, .src index files across 32-bit and 64-bit architectures.
* Completely resolved CPAN Testers "Invalid type 'Q' in pack" exceptions across 36 test suites.
- [CLI THREE-MODE ARCHITECTURE & ZERO-FALLBACK ENFORCEMENT]
* Re-architected amberdb CLI (bin/amberdb_cli.pl) into three distinct, predictable operational modes:
1. 'amberdb setup': Provisions global workspace (~/.amberdb) with session/ and config/ directories. Fully eliminated dummy default/ database.
2. 'amberdb connect <name>[@<path>]': Named session management with canonical absolute path resolution; rejects raw directory names without database alias.
3. Direct CRUD ('amberdb CRUD'): Strictly targets local ./dbstore in current working directory without fallback to ~/.amberdb/default.
* Read operations (tables, read, search, count, info) return empty/null cleanly without creating directory skeletons.
* Write operations (insert) automatically provision ./dbstore and core.conf on-the-fly.
* Updated user guides and documentation in README.md, wiki/TR-Guide-CLI.md, and wiki/Guide-CLI.md.
- [SCHEMA USE_SIMPLE SANITIZATION & STRING KEY PRESERVATION]
* Updated AmberDB::Base::Schema to strip unused 'blocks' definition for use_simple => 1 tables.
* Wrapped explicit ID sorting in AmberDB::insert_list with unless ($is_simple) guard, eliminating numeric comparison warnings on string keys without regex overhead.
* Fixed macOS /Volumes permission error in AmberDB::Base::Ramdisk by verifying write permissions before activating RAM-disk mount points.
* Added eval guard to ramdisk_setup with graceful fallback to local storage.
- [WINDOWS CRLF & TRANSACTION JOURNAL HARDENING]
* Enforced binmode on journal handles in AmberDB::Base::Transact to prevent Windows CRLF mangling of record separators and Base64 payloads.
* Added journal content diagnostic dumps and exact field assertions in t/amberdb_transact.t.
- [WINDOWS CI & FLOCK / CLI AT-SYNTAX COMPATIBILITY]
* Replaced colon separator with '@' for custom directory connect syntax ('amberdb connect <dbname>@<path>'), completely eliminating ambiguity with Windows drive letters (C:\path).
* Enforced strict directory path and legacy colon syntax rejection in bin/amberdb_cli.pl.
* Added automatic background workspace provisioning in bin/amberdb_cli.pl: automatically runs global setup on first invocation if ~/.amberdb does not exist.
* Fixed t/amberdb_transact.t journal reader to read directly via active transaction handle ($adb->{_txn}->{fh}), eliminating Windows mandatory flock(LOCK_EX) read collisions that resulted in uninitialized $journal_content on native Windows ...
* Added comprehensive cross-platform connect '@' syntax, auto-setup, and Windows drive path rejection tests in t/amberdb_cli.t.
5.26.0 2026-09-23
- [FAST INDEXED FIELD COUNTING (field_count)]
* Implemented field_count($table, $block, $val) for fast O(1) indexed counting across inverted match (.fld) indexes without reading or deserializing full records.
* Optimized for high-throughput facet counts, inventory status aggregation, and relational child counts.
* Added comprehensive unit test suite in t/amberdb_field_count.t and documentation in wiki/Method-field_count.md and wiki/TR-Method-field_count.md.
- [COLUMNAR FACETS & BIDIRECTIONAL DICTIONARY LOOKUP]
* Replaced direct hash access with fast accessor methods across dump, vacuum, and backup routines.
- [DIRECTORY ARCHITECTURE & LOCK PATH STANDARDIZATION]
* Standardized lock_dir and session_dir as single-key directories in AmberDB::Base::Ramdisk and AmberDB::Base.
* Removed obsolete fallback keys (lock_rdir) and legacy naming aliases (conf_dir, cfg_dir).
* In RAM-disk environments, lock_dir and session_dir are dynamically mounted under $ramdisk_dir/lock and $ramdisk_dir/session with 0755 permissions; when unmounted, they reside cleanly under $dbase_dir/lock and $dbase_dir/session.
* Aligned database lock directory structures with inter-process state locking specifications.
- [SCHEMA LOADING RESILIENCE]
* Wrapped 'do $target_path' inside eval { do $target_path } in AmberDB::Base::Schema (table_info() and dbase_info()).
* Prevents fatal process/worker termination when user .table or .dbase schema files contain syntax errors under global $SIG{__DIE__} handlers.
- [SLUG INDEX ARCHITECTURE VERIFICATION (.slg)]
* Verified flat unified .slg index access model where block numbers (formerly _0 / _1 file suffixes) reside in key prefixes:
- Block 0: "0:$rid" -> URL slug value
- Block 1: "1:$slug" -> Record ID value
* Enforced direct .slg table access and recs_get key lookups without legacy .rwt fallbacks.
- [GROUP-LEVEL SCHEMA INHERITANCE (.dbase -> .table)]
* Database group schema files (.dbase) now cascade common operational flags to all member tables in the group.
* Added %INHERITABLE_DBASE_KEYS whitelist in AmberDB::Base::Schema (use_ramdisk, keep_deleted, use_counter, log_owner, table_dir, use_section, etc.) preventing table-specific blocks and rules from leaking.
- AmberDB::Base::Facet (Faceted search and category aggregation)
- AmberDB::Base::Junk (Multi-tiered soft-delete and junk rule processing)
- AmberDB::Base::Transact (WAL transaction engine and atomic journaling)
* Excluded entire lib/AmberDB/Base/ directory and AmberDB::Base namespace from CPAN indexing in Makefile.PL (no_index), keeping MetaCPAN documentation clean and focused on public standalone interfaces.
* Consolidated public submodule architecture in AmberDB POD to focus exclusively on standalone components (AmberDB::Date, AmberDB::Locale, AmberDB::Tools).
* Integrated ISO 4217 Currency Dictionary documentation into AmberDB::Locale and removed standalone POD from internal AmberDB::Locale::Currency to prevent separate CPAN indexing.
* Removed unused legacy String utility module; consolidated trim_space utility into AmberDB::Base.
- [TRANSPARENT PHYSICAL RAM-DISK ACCELERATION & CROSS-PLATFORM ORCHESTRATION]
* Cross-Platform Support (Linux, macOS, Windows): Standardized bin/ramdisk_* suite (ramdisk_amberdb.pl, ramdisk_windows.bat/ps1, ramdisk_macos.sh, ramdisk_linux.sh) with native support for Linux tmpfs, macOS APFS RAM-Disk (hdiutil), and Win...
* Global & Per-Table Acceleration: Supports global use_ramdisk => 1|2 in AmberDB->new with per-table overrides (use_ramdisk => 0|1|2|3) and lazy preloading on first table access.
* Volatile Pure RAM-Disk Mode (Tier 3 & ramdisk_ttl): Supports memory-only unindexed tables (use_ramdisk => 3, use_simple => 1) with configurable sliding time-to-live expiration (ramdisk_ttl, default 300s).
* Custom Storage Subfolder Organization (table_dir): Allows routing table and index files to dedicated subfolders (e.g. table_dir => 'orders') or directly to the database root (table_dir => '').
* Standardized Path & Environment Options (dbase_dir): Engine root storage path formalized with full runtime reflection and set_datadir migration.
* Standardized RAM-Disk Parameters: Replaced legacy cache_size and cache_dir with ramdisk_size and ramdisk_dir across constructor, config, and diagnostic reporting.
* Native File Extension Architecture: RAM-disk stores all database and index files with their native extensions (.db, .inx, .fld, .src, .fac, .unq, .slg), retiring proprietary .cache file formats.
* Unified ramdisk_setup([$tableid]): Consolidated environment validation, mount diagnostics, and deterministic table preloading into a single method ($adb->ramdisk_setup), superseding legacy cache_setup and cache_preload.
* Dedicated L1 Process Cache API: Replaced legacy cache_* routines with clean, dedicated get_cache and set_cache methods for in-memory L1 storage.
* Hardened Mount Detection: Validates symlinks/junctions (-l) and direct RAM paths with zero-subprocess /proc/mounts verification, auto-registered to $adb->config('ramdisk_mounted').
* Dual-Write & Transaction Safety: Real-time dual-write across index and data files with atomic Berkeley DB preloading and WAL rollback protection.
* Decoupled Engine Architecture: Separated AmberDB::Base::Ramdisk (physical file storage) from AmberDB::Base::Cache (in-memory L1 cache and staging buffers).
* All 47 test files (440 assertions) passing with 100% success rate.
5.23.2 2026-09-03
- [LOCALE ENGINE & MULTILINGUAL ARCHITECTURE] 10th Language - Global Base (gb) and Default Locale:
* Introduced Global Base (gb) as the 10th supported language and new universal default/fallback locale (replacing en).
* Implemented comprehensive multilingual Latin character preservation in alphabet_chars across European, Turkish, Nordic, French, German, Spanish, and Slavic-Latin alphabets.
* Added cross-lingual, accent-tolerant search regex mapping (regex_map) matching accented and unaccented variations (e.g. cafe matches café, munchen matches münchen, seker matches Åeker).
* Implemented canonical accent folding in accent_map for high-recall inverted search indexing (.src).
* Added lossless Unicode ligature conversion in ascii_map (Ã->ss, æ->ae, Å->oe, ı->i, ø->o, Å->l, Ä->d, ð->d, þ->th, É->e) for clean URL slug and ASCII ID generation.
* Configured international English numbering, date formatting, and ISO standard decimal/group separators.
* Added language aliases: 'gb', 'global', 'gl', 'universal', 'uni', 'gb_base'.
* Added dedicated test coverage in t/amberdb-locale_09_gb.t.
- [TRANSACTION ARCHITECTURE & API REFINEMENT] Pure File-Path Error Model and Operational Rollback:
* Refactored transact_error($file_path, $message) to exclusively accept physical file paths; eliminated artificial "transaction" and "system" string contexts.
* Simplified table identification via single exact regex /([^\/\\:]+)\.$db_ext$/: directly extracts table ID and inspects schema no_transact attribute; non-db extensions (.inx, .src, .fld, .fac, .slg, .aut, .del, .txn) never trigger rollbac...
* Added immediate early return in transact_error if $file_path is undefined or empty.
* Established strict API role separation: application code directly invokes transact_rollback() for business logic cancellations (insufficient stock, credit limits, validation aborts) and unexpected eval exceptions; transact_error is reserv...
* Unified legacy is_index and is_no_transact flags into single no_rollback attribute.
* Restructured insert_id to strictly validate mandatory $tableid at entry prior to resolving table paths, with proper ref guard for $rid.
5.23.1 2026-09-02
* Implemented hash_diff($hash1, $hash2) in AmberDB::Array with safe shallow copying, ensuring input hash structures are never mutated.
* Removed legacy internal _hash_diff from AmberDB::Tools and switched to $adb->hash_diff directly.
* Added unit test coverage for hash_diff in t/amberdb_array.t.
5.22.2 2026-09-01
- [CROSS-PLATFORM & CI] Universal GitHub Actions CI Matrix:
* Configured multi-platform CI matrix testing on Linux (ubuntu-latest), macOS (macos-latest), and Windows (windows-latest) across Perl 5.16 through 5.40.
* Configured official Strawberry Perl distribution in CI for native Berkeley DB / DB_File binary compatibility and prevented Git Bash PATH collisions.
- [STORAGE & TRANSACTIONS] Safe Directory Scanner and Windows File Sharing:
* Introduced dir_files($dir, [$pattern], [%opts]) helper method in AmberDB::Base for cross-platform, safe file discovery supporting wildcards (*.db, txn_*.txn) and compiled regular expressions (qr/../).
* Refactored AmberDB::Transact and AmberDB::Tools (dir_tables, all_tables, del_table) to use dir_files, completely removing fragile glob usage.
* Fixed Windows NTFS file sharing collision in transact_recover: journal lines are now read directly from open locked handles, preventing secondary open permission denied errors.
- [TESTS & STABILITY] Test Concurrency and Monotonic Sequence:
* Hardened t/amberdb_transact.t orphan recovery subtest to use strictly monotonic table_autoid record IDs (65) and authentic transaction lifecycle simulation.
* Guaranteed complete handle and lock cleanup with $adb->close_all() in crash recovery test scenarios.
5.22.1 2026-09-01
- [DOCS] Documentation and Synopsis Fixes:
* Fixed synopsis and API example signatures across documentation and POD.
* Updated README.md installation instructions with streamlined CPAN/cpanm cross-platform support.
* Fixed character encoding and wide-character warnings in test suite schemas.
bin/amberdb_cli.pl view on Meta::CPAN
# ============================================================================
# SESSION REGISTRY (~/.amberdb/session/)
# Stores session files per active session under ~/.amberdb/session/sess_$token
# ============================================================================
my $user_home = $ENV{USERPROFILE} // $ENV{HOME} // '.';
$user_home =~ s{\\}{/}g;
our $AMBERDB_HOME = "$user_home/.amberdb";
our $CLI_SESS_DIR = "$AMBERDB_HOME/session";
sub setup_global_workspace {
eval {
make_path($AMBERDB_HOME) unless -d $AMBERDB_HOME;
make_path($CLI_SESS_DIR) unless -d $CLI_SESS_DIR;
my $cfg_dir = "$AMBERDB_HOME/config";
make_path($cfg_dir) unless -d $cfg_dir;
};
}
# Auto-provision global workspace in background on first run if missing
if ( !-d $AMBERDB_HOME ) {
setup_global_workspace();
}
sub resolve_abs_path {
my ($path) = @_;
return '' unless defined $path && length $path;
$path =~ s{\\}{/}g;
my $abs = eval { abs_path($path) };
if ( defined $abs && length $abs ) {
$abs =~ s{\\}{/}g;
return $abs;
bin/amberdb_cli.pl view on Meta::CPAN
amberdb delete users 10
2. İsimlendirilmiŠOturum (Session Management):
amberdb connect <database> # ~/.amberdb/<database> havuzuna baÄlanır
amberdb connect <database>\@<path> # Ãzel bir klasöre baÄlanır (örn: mydb\@./dbstore)
amberdb 1245 tables # 1245 nolu oturumun tablolarını listeler
amberdb 1245 read products 10 # 1245 nolu oturumda okuma yapar
amberdb 1245 disconnect # Oturumu sonlandırır
3. Altyapı ve Kurulum:
amberdb setup # ~/.amberdb global çalıÅma alanını kurar
amberdb setup [dir] # Ãzel bir dizinde veritabanı iskeleti kurar
amberdb setup ramdisk [start|stop|status] # RAM-disk sürücü yönetimi
Bakım ve Yönetim Eylemleri:
amberdb update storage [--check] [--force] # Dizin & ABR v5 veri biçimi migrasyonu
amberdb update version [--check] # MetaCPAN çekirdek sürüm kontrolü / güncelleme
amberdb reindex products # İndeksleri sıfırdan oluÅtur
amberdb check products # Fiziksel dosya bütünlük kontrolü
amberdb vacuum products # BDB disk boÅluklarını temizle
amberdb migrate products # Åema güncellemesi
bin/amberdb_cli.pl view on Meta::CPAN
amberdb delete users 10
2. Named Session (Session Management):
amberdb connect <database> # Connect to ~/.amberdb/<database> pool
amberdb connect <database>\@<path> # Connect to custom folder (e.g. mydb\@./dbstore)
amberdb 1245 tables # List tables for session 1245
amberdb 1245 read products 10 # Read record in session 1245
amberdb 1245 disconnect # Terminate active session
3. Infrastructure & Setup:
amberdb setup # Provision ~/.amberdb global workspace
amberdb setup [dir] # Initialize database skeleton in custom directory
amberdb setup ramdisk [start|stop|status] # RAM-disk drive management
Maintenance & Administrative Actions:
amberdb update storage [--check] [--force] # Directory & ABR v5 format migration
amberdb update version [--check] # MetaCPAN core version check / update
amberdb reindex products # Rebuild all derived indexes
amberdb check products # Physical file integrity check
amberdb vacuum products # Compact and reclaim BDB storage space
amberdb migrate products # Schema migration
bin/amberdb_cli.pl view on Meta::CPAN
delete_session($token);
if ( defined $opt_format && $opt_format eq 'json' ) {
print encode_json( { status => 'disconnected', token => $token } ), "\n";
}
else {
print "[AMBERDB] Disconnected session '$token' successfully.\n";
}
exit 0;
}
# If in session and global configs/paths changed without action, update session and exit
if ( $session && ( $has_cfg_updates || $has_path_updates ) && !defined $opt_action ) {
$session->{path} = $adb->path();
$session->{cfg} = $adb->config();
$session->{updated_at} = time();
save_session( $active_token, $session );
if ( defined $opt_format && $opt_format eq 'json' ) {
print encode_json( { status => 'updated', token => $active_token, path => $adb->path(), cfg => $adb->config() } ), "\n";
}
else {
bin/amberdb_cli.pl view on Meta::CPAN
print "[RAM-DISK] Linux /dev/shm initialized.\n";
exit 0;
}
elsif ( $subcmd eq 'stop' ) {
print "[RAM-DISK] Stopped.\n";
exit 0;
}
}
}
# If no argument is passed: setup global environment (~/.amberdb)
if ( !defined $first_arg || !length $first_arg ) {
setup_global_workspace();
if ( defined $opt_format && $opt_format eq 'json' ) {
output_result( {
status => 'ok',
action => 'setup',
mode => 'global',
amberdb_home => $AMBERDB_HOME,
session_dir => $CLI_SESS_DIR,
}, $opt_format );
exit 0;
}
print "=================================================================\n";
print " AmberDB Global Environment Setup & Initialization \n";
print "=================================================================\n";
print "AmberDB Home : $AMBERDB_HOME (~/.amberdb)\n";
print "Session Registry : $CLI_SESS_DIR/\n";
print "Platform : $^O\n";
print "-----------------------------------------------------------------\n";
print "[SUCCESS] AmberDB global workspace initialized successfully!\n\n";
print "Kullanım Biçimleri:\n";
print " 1. Yerel Proje : Proje klasörünüzde doÄrudan çalıÅtırın (./dbstore kullanılır)\n";
print " amberdb insert users 0 data='{\"name\":\"Ahmet\"}'\n";
print " amberdb tables\n\n";
print " 2. Merkezi Havuz : Belirtilen ada oturum açarak ~/.amberdb/<ad> kullanılır\n";
print " amberdb connect eticaretim\n";
print " amberdb 1245 tables\n\n";
print " 3. Ãzel Klasör : 'ad\@yol' formatı ile oturum açılır\n";
print " amberdb connect eticaretim\@./dbstore\n";
print "=================================================================\n";
docs/EN.AmberDB-Locale_User-Guide.md view on Meta::CPAN
# 3) Positional string API
my $lang = AmberDB::Locale->new("fr");
# 4) No args â defaults to "gb" (Global Base)
my $lang = AmberDB::Locale->new();
```
### Internal behaviors
- **Caching:** A second `new()` call for the same language returns the existing instance (singleton-like).
- **Alias support:** Labels like `"global"`, `"gl"`, `"turkish"`, `"tr_tr"`, `"tr-tr"` are automatically mapped to canonical codes.
- **Fallback:** If an unknown language is requested, a `cluck` warning is emitted and it falls back to `gb`.
- **Collator:** Attempts to load `Unicode::Collate::Locale`; if it fails, falls back to base `Unicode::Collate`, and if that's also unavailable, uses a custom `sort_map` Schwartzian transform.
### AmberDB integration
```perl
# Language is automatically pulled from cfg
my $db = AmberDB->new(cfg => { language => "tr" });
$db->uc("ıÄdır"); # works via inheritance: IÄDIR
```
docs/EN.AmberDB_User-Guide.md view on Meta::CPAN
#### 1. Global Configuration (Default for All Tables)
You can enable index or full-table acceleration across the entire database in one step:
```perl
# Apply Tier 1 (Hybrid Index) to all tables upon initialization
my $adb = AmberDB->new(
cfg => { use_ramdisk => 1 },
path => { dbase_dir => "/var/data/amberdb" }
);
# Dynamically change global tier at runtime
$adb->config(use_ramdisk => 2); # Switch all tables to Tier 2 (Full Mirror)
```
#### 2. Per-Table Flexible Configuration and Overrides
Each table can be independently assigned its own acceleration tier in its `.table` schema file or at runtime via `table_attr()`:
```perl
# Put high-traffic categories table into Full RAM-Disk Mirroring
$adb->table_attr("catalog_category", use_ramdisk => 2);
docs/TR.AmberDB-Locale_Kullanim_Rehberi.md view on Meta::CPAN
# 3) Pozisyonel string API
my $lang = AmberDB::Locale->new("fr");
# 4) Argümansız â varsayılan "gb" (Global Base)
my $lang = AmberDB::Locale->new();
```
### Dahili davranıÅlar
- **Ãnbellekleme:** Aynı dil için ikinci `new()` çaÄrısı mevcut nesneyi döndürür (singleton benzeri).
- **Alias desteÄi:** `"global"`, `"gl"`, `"turkish"`, `"tr_tr"`, `"tr-tr"` gibi etiketler otomatik olarak eÅlenir.
- **Fallback:** Bilinmeyen bir dil istenirse `cluck` ile uyarı verilir ve `gb`'ye düÅülür.
- **Collator:** `Unicode::Collate::Locale` yüklenmeye çalıÅılır; baÅarısız olursa `Unicode::Collate` tabanına, o da yoksa özel `sort_map` Schwartzian transform'una düÅülür.
### AmberDB entegrasyonu
```perl
# cfg üzerinden dil otomatik çekilir
my $db = AmberDB->new(cfg => { language => "tr" });
$db->uc("ıÄdır"); # kalıtım yoluyla çalıÅır
```
docs/TR.AmberDB_Veritabani_Sistemi.md view on Meta::CPAN
#### 1. Global Yapılandırma (Tüm Tablolar İçin Varsayılan)
Tüm veritabanı genelinde indeks veya tam tablo hızlandırmasını tek seferde etkinleÅtirebilirsiniz:
```perl
# Kurulum anında tüm tablolara Seviye 1 (Hibrit İndeks) uygulama
my $adb = AmberDB->new(
cfg => { use_ramdisk => 1 },
path => { dbase_dir => "/var/data/amberdb" }
);
# ÃalıÅma anında global seviyeyi deÄiÅtirme
$adb->config(use_ramdisk => 2); # Tüm tabloları Seviye 2 (Tam Ayna) yap
```
#### 2. Tablo Bazında Esnek Yapılandırma ve İstisnalar
Her tablo için `.table` Åema dosyasından veya çalıÅma anında `table_attr()` ile baÄımsız hızlandırma seviyesi belirlenebilir:
```perl
# Yüksek trafikli kategoriler tablosunu Tam RAM Aynasına al
$adb->table_attr("catalog_category", use_ramdisk => 2);
# Seyrek eriÅilen bir tabloyu global RAM-disk kapsamı dıÅına çıkar (diskte tut)
$adb->table_attr("audit_archive", use_ramdisk => 0);
```
#### 3. Standart CRUD ÃaÄrılarıyla DoÄrudan Kullanım
GeliÅtirici yalnızca standart AmberDB metotlarını kullanır. Motor, arka planda RAM-disk kopyalamasını, bellekten okumayı ve diske çift yazmayı Åeffaf olarak yürütür:
```perl
# Okuma: use_ramdisk tanımlıysa sorgular doÄrudan RAM üzerinden mikrosaniyede döner
my @urun = $adb->read_id("catalog_product", 101);
my ($adet, @sonuclar) = $adb->search_table("catalog_product", "kablosuz kulaklik");
lib/AmberDB.pm view on Meta::CPAN
}
for my $child_table ( keys %children ) {
$self->table_truncate($child_table);
}
return scalar keys %children;
}
# Sanitizes and validates a record ID according to table mode.
# If simple mode (global simple or table use_simple): allows safe arbitrary keys (max 255 bytes, no control chars).
# If standard mode: strictly enforces positive integer numeric ID.
# my $clean_id = $adb->id_check($tableid, $rid);
# ------------------------------------------------
sub id_check {
my ( $self, $tableid, $rid ) = @_;
return unless defined $rid && $rid ne '';
return if ref $rid;
my $table_info = $tableid ? $self->table_info($tableid) : {};
lib/AmberDB.pm view on Meta::CPAN
$self->index_del( [ $mirror_path, $tableid, 1 ], \@keys_to_del );
}
}
}
}
return $del_count;
}
# Writes add|edit|del operation to daily CSV backup audit stream (backup/YYYY/YYYY-MM-DD.csv).
# Exits silently if no_backup is set (globally or in table schema).
# my $ok = $adb->recs_back("add|edit|del", $tableid, @records);
# ------------------------------------------------
sub recs_back {
my ( $self, $action, $tableid, @records ) = @_;
( $action and $tableid and scalar @records ) or return;
# Global config check: disables backup for all tables
return 1 if $self->config('no_backup');
lib/AmberDB.pm view on Meta::CPAN
=item * B<Tier 4 (Asynchronous Write-Behind, C<use_ramdisk =E<gt> 4>):> Primary records and indexes are updated immediately in RAM-disk for maximum throughput. Write operations append dirty sync events to C<journal/sync_ramdisk>, and a background dae...
=back
=head2 Transparent Management (C<use_ramdisk>)
AmberDB manages the RAM-disk layer entirely in the background. Developers do not need to call any low-level RAM-disk functions or manually orchestrate memory synchronization. Everything is controlled declaratively via the C<use_ramdisk> option:
=over 4
=item * B<Global Configuration:> Set globally at instantiation (C<AmberDB-E<gt>new(cfg =E<gt> { use_ramdisk =E<gt> 1 })>) or at runtime via C<$adb-E<gt>config(use_ramdisk =E<gt> 2)>.
=item * B<Per-Table Customization:> Set independently for each table in its C<.table> schema or via C<$adb-E<gt>table_attr($table, use_ramdisk =E<gt> $tier)>.
=item * B<Standard CRUD Workflow:> Continue using standard AmberDB methods (C<read_id>, C<search_table>, C<insert_id>, C<modify_id>). The engine automatically reads from memory at microsecond speeds and dual-writes to permanent storage.
=item * B<Windows & Linux Administration:> On Windows, use C<bin\setup_windows.bat> to mount or unmount the ImDisk RAM-disk. On Linux, C</dev/shm> is utilized automatically:
- Mount RAM-disk (Windows): bin\setup_windows.bat start 512M R:
- Status check (Windows): bin\setup_windows.bat status
- Background Sync Daemon: perl bin/amberdb_daemon.pl start
lib/AmberDB/Base.pm view on Meta::CPAN
my %pairs = ( @args == 1 && ref( $args[0] ) eq 'HASH' ) ? %{ $args[0] } : @args;
for my $key ( keys %pairs ) {
$self->{_path}->{$key} = $pairs{$key};
}
$self->_invalidate_table_paths();
return $self;
}
# Invalidate cached table paths if global path-affecting configurations change
# ------------------------------------------------
sub _invalidate_table_paths {
my ($self) = @_;
if ( $self->{_table} && ref( $self->{_table} ) eq 'HASH' ) {
for my $tbl ( keys %{ $self->{_table} } ) {
delete $self->{_table}->{$tbl}->{_path}
if ref( $self->{_table}->{$tbl} ) eq 'HASH';
}
}
lib/AmberDB/Base/Schema.pm view on Meta::CPAN
# ------------------------------------------------------------------------
$self->_apply_dbase_inheritance( $table, $schema );
# ------------------------------------------------------------------------
# Pipeline Step 1: Global Configuration Inheritance
# ------------------------------------------------------------------------
if ( defined $schema->{use_ramdisk} ) {
$schema->{use_ramdisk} = $self->_normalize_ramdisk_tier( $schema->{use_ramdisk} );
}
elsif ( !defined $schema->{use_cache} ) {
my $global_ram = $self->config('use_ramdisk');
$global_ram = $self->_normalize_ramdisk_tier($global_ram);
$global_ram = 0 if $global_ram == 3;
$schema->{use_ramdisk} = $global_ram;
}
# ------------------------------------------------------------------------
# Pipeline Step 1b: Volatile RAM-Disk Tier 3 Stripping
# If use_ramdisk == 3, table is pure volatile key-value store on RAM-disk.
# Strip all indexing, columnar, facet, and relational definitions.
# ------------------------------------------------------------------------
if ( ( $schema->{use_ramdisk} // 0 ) == 3 ) {
delete @{$schema}{
qw(
lib/AmberDB/Locale.pm view on Meta::CPAN
'es_es' => 'es',
'russian' => 'ru',
'ru_ru' => 'ru',
'arabic' => 'ar',
'ar_sa' => 'ar',
'azerbaijani' => 'az',
'az_az' => 'az',
'japanese' => 'ja',
'ja_jp' => 'ja',
'ja-jp' => 'ja',
'global' => 'gb',
'gb' => 'gb',
'gl' => 'gb',
'universal' => 'gb',
'uni' => 'gb',
'gb_base' => 'gb',
);
$lang = lc( $lang // '' );
$lang =~ s/[^\w-]//g;
my $norm_lang = $LANG_ALIAS{$lang} || ( split /[_-]/, $lang )[0] || 'gb';
lib/AmberDB/Locale.pm view on Meta::CPAN
return 0 unless defined $cond && length $cond;
my $n = abs( $count // 0 );
# Whitelist strictly only digits, 'n', whitespace, arithmetic and logical operators
return 0 unless $cond =~ /^[n0-9+\-*\/%&|!=<>()\s]+$/;
# Replace 'n' variable token with actual numeric value
( my $expr = $cond ) =~ s/\bn\b/$n/g;
# Safely evaluate numeric expression isolated from global DIE handlers
my $res = eval {
local $SIG{__DIE__} = sub {};
eval $expr; ## no critic
};
return $res ? 1 : 0;
}
# -------------------------------------------------------
# Evaluate CLDR plural rule and select template.
#
lib/AmberDB/Locale.pm view on Meta::CPAN
# 2. Hashref API
my $lang = AmberDB::Locale->new({ language => 'de' });
# 3. Positional string API
my $lang = AmberDB::Locale->new('fr');
# 4. Default (falls back to Global Base 'gb')
my $lang = AmberDB::Locale->new();
Supported language codes include C<"gb"> (Global Base - default), C<"tr">, C<"en">, C<"de">, C<"fr">, C<"es">, C<"ru">, C<"az">, C<"ar">, C<"ja"> and common aliases (such as C<"global">, C<"turkish">, C<"tr_tr">, C<"english">, C<"german">, etc.).
If an unsupported language is specified, a warning is issued and the instance falls back to C<"gb">.
=head1 METHODS
=head2 Case Conversions & Comparison
=head3 uc($string)
Converts C<$string> to uppercase according to locale-specific casing rules.
lib/AmberDB/Tools/Update.pm view on Meta::CPAN
sub replace_tablename {
my ( $self, $find, $replace ) = @_;
my $adb = $self->{_adb} or return;
my @tables;
my $dbase_dir = $adb->path('dbase_dir') || ".";
my $year_dir = $adb->path('year_dir') || "";
if ( $adb->config('simple') ) {
@tables = glob "$dbase_dir/$find.*";
push @tables, ( glob "$dbase_dir/${find}_*" );
}
else {
@tables = glob "$dbase_dir/table/$find.*";
push @tables, ( glob "$dbase_dir/table/${find}_*" );
if ( $adb->config('use_section') ) {
my @sections = glob "$dbase_dir/section_*";
foreach my $sec_file (@sections) {
push @tables, ( glob "$sec_file/$find.*" );
push @tables, ( glob "$sec_file/${find}_*" );
}
}
if ( $adb->config('use_year') && $year_dir ) {
@tables = glob "$dbase_dir/$year_dir/$find.*";
push @tables, ( glob "$dbase_dir/$year_dir/${find}_*" );
if ( $adb->config('use_section') ) {
my @sections = glob "$dbase_dir/$year_dir/section_*";
foreach my $sec_file (@sections) {
push @tables, ( glob "$sec_file/${find}.*" );
push @tables, ( glob "$sec_file/${find}_*" );
}
}
}
}
foreach my $old_file (@tables) {
my $new_file = "$old_file";
$new_file =~ s/\/$find([\.\_])/$replace$1/;
rename( $old_file, $new_file );
}
t/amberdb-locale_09_gb.t view on Meta::CPAN
plan tests => 7;
# Default constructor without arguments must return 'gb'
my $def = AmberDB::Locale->new();
is( $def->language, 'gb', 'Default constructor resolves to gb' );
# Explicit 'gb'
my $gb = AmberDB::Locale->new( language => 'gb' );
is( $gb->language, 'gb', 'Explicit language => gb resolves to gb' );
# Alias 'global'
my $global = AmberDB::Locale->new( language => 'global' );
is( $global->language, 'gb', 'Alias language => global resolves to gb' );
# Alias 'gl'
my $gl = AmberDB::Locale->new( language => 'gl' );
is( $gl->language, 'gb', 'Alias language => gl resolves to gb' );
# Alias 'universal'
my $uni = AmberDB::Locale->new( language => 'universal' );
is( $uni->language, 'gb', 'Alias language => universal resolves to gb' );
# Positional string
t/amberdb-locale_09_gb.t view on Meta::CPAN
plan tests => 8;
my $tmpdir = tempdir( CLEANUP => 1 );
my $adb = AmberDB->new(
path => { dbase_dir => $tmpdir },
);
is( $adb->language, 'gb', 'AmberDB instance initializes with gb language by default' );
is( $adb->config('language'), 'gb', 'AmberDB config("language") defaults to gb' );
my $tbl = 'global_catalog';
$adb->table_attr( $tbl, {
record_index => 1,
search_block => [ 2, 3 ], # Title, Desc
});
# Insert items in multiple languages
$adb->insert_id( $tbl, 1, 'SKU-1', 'French Café Roastery', 'Artisan espresso blend' );
$adb->insert_id( $tbl, 2, 'SKU-2', 'München Weissbier Glass', 'Traditionelles Glas aus Bayern' );
$adb->insert_id( $tbl, 3, 'SKU-3', 'Türk Lokumu Åekerleme', 'Geleneksel antep fıstıklı tatlı' );
t/amberdb_cli.t view on Meta::CPAN
# Read session file content
open my $fh, '<', $sess_file;
local $/;
my $sess_json = <$fh>;
close $fh;
my $sess_data = decode_json($sess_json);
is($sess_data->{cfg}->{language}, 'tr', "Config language 'tr' saved in session");
};
# ---------------------------------------------------------------------------
subtest '3. Dash tolerance & global config update' => sub {
plan tests => 4;
# Connect to get token
my $out_conn = `"$perl_bin" -Ilib "$cli_path" connect path-dbase_dir="$test_dbdir" format=json`;
my $conn = eval { decode_json($out_conn) };
my $token = $conn ? $conn->{token} : '';
# Update with --cfg-no_write=1 (double dash)
my $upd1 = `"$perl_bin" -Ilib "$cli_path" --token=$token --cfg-no_write=1 format=json 2>&1`;
my $data1 = eval { decode_json($upd1) };
t/amberdb_ramdisk_tiers.t view on Meta::CPAN
is( $adb->config('use_ramdisk'), 1, "config('index') normalizes to 1" );
$adb->config( use_ramdisk => 'none' );
is( $adb->config('use_ramdisk'), 0, "config('none') normalizes to 0" );
$adb->config( use_ramdisk => 'async' );
is( $adb->config('use_ramdisk'), 4, "config('async') normalizes to 4" );
# Global Tier 3 fallback to 0
$adb->config( use_ramdisk => 'temp' );
is( $adb->config('use_ramdisk'), 0, "config('temp') falls back to 0 globally" );
$adb->config( use_ramdisk => 'volatile' );
is( $adb->config('use_ramdisk'), 0, "config('volatile') falls back to 0 globally" );
# 3. Table attribute string normalization
$adb->table_attr( 'tbl_none', use_ramdisk => 'none' );
$adb->table_attr( 'tbl_index', use_ramdisk => 'index' );
$adb->table_attr( 'tbl_dual', use_ramdisk => 'dual' );
$adb->table_attr( 'tbl_temp', use_ramdisk => 'temp' );
$adb->table_attr( 'tbl_async', use_ramdisk => 'async' );
is( $adb->table_attr( 'tbl_none', 'use_ramdisk' ), 0, "table_attr('none') normalizes to 0" );
is( $adb->table_attr( 'tbl_index', 'use_ramdisk' ), 1, "table_attr('index') normalizes to 1" );
t/amberdb_simple_mode.t view on Meta::CPAN
my @read = $adb->read_id( 'sessions', $id );
is( $read[0], $id, "read_id returned exact ID: $id" );
is( $read[1], 'Active', "read_id field 1 matches for $id" );
my $exists = $adb->exist_id( 'sessions', $id );
is( $exists, 1, "exist_id confirms key exists: $id" );
}
# Verify that ONLY sessions.db was created, NO index files (.inx, .fld, .src, .srt, .fac, .slg)
my @created_files = glob("$db_dir/*");
my @index_files = grep { /\.(inx|fld|src|srt|fac|slg)$/ } @created_files;
is_deeply( \@index_files, [], 'No index files (.inx, .fld, .src, .srt, .fac, .slg) generated' );
};
# ============================================================
# 2. CRUD Operations with Arbitrary IDs
# ============================================================
subtest '2. CRUD Lifecycle & Bulk Operations in Simple Mode' => sub {
my $db_dir = "$tmp_dir/simple_db2";
mkdir($db_dir);
t/amberdb_table_use_simple.t view on Meta::CPAN
ok( $del_res, 'delete_id succeeded' );
my @after_del = $adb->read_id( 'sessions', $del_key );
ok( !@after_del, 'Deleted record not returned by read_id' );
# Check that .del archive file exists and contains the deleted record
my $del_file = "$db_dir/table/sessions.del";
ok( -e $del_file, 'sessions.del archive created by keep_deleted' );
# Check that NO index files exist for sessions
my @all_files = glob("$db_dir/table/*");
my @index_files = grep { /sessions\.(inx|fld|src|srt|fac|slg)$/ } @all_files;
is_deeply( \@index_files, [], 'No index files (.inx, .fld, .src, .srt, .fac, .slg) created for sessions' );
};
# ============================================================
# 4. Foreign Key (RDBM) & field_fetch Protection
# ============================================================
subtest '4. Foreign Key (RDBM) Guarding & field_fetch Unindexed Scan' => sub {
plan tests => 5;
xt/amberdb_ramdisk.t view on Meta::CPAN
my $init_db = AmberDB->new(
database => 'catalog',
path => { dbase_dir => $g_tmp }
);
$init_db->insert_id( 'catalog_books', 1, 'Book One' );
$init_db->insert_id( 'catalog_authors', 10, 'Author Ten' );
$init_db->insert_id( 'catalog_excluded', 99, 'Excluded Data' );
}
# 2. Open with global cfg => { use_ramdisk => 1 }
my $adb_g1 = AmberDB->new(
database => 'catalog',
cfg => { use_ramdisk => 1 },
path => { dbase_dir => $g_tmp, ramdisk_dir => $g_ram }
);
# Access catalog_books via table_path
my $b_path = $adb_g1->table_path('catalog_books');
my $b_ram = $adb_g1->ramdisk_path('catalog_books');
ok( -e "$b_ram.inx", 'Global use_ramdisk => 1 preloads .inx to RAM-disk on table_path' );
ok( !-e "$b_ram.db", 'Global use_ramdisk => 1 does NOT copy .db (data remains on disk)' );
is( ($adb_g1->read_id('catalog_books', 1))[1], 'Book One', 'read_id works seamlessly' );
# Access catalog_authors via table_info
my $a_info = $adb_g1->table_info('catalog_authors');
my $a_ram = $adb_g1->ramdisk_path('catalog_authors');
is( $a_info->{use_ramdisk}, 1, 'Table inherits global use_ramdisk => 1' );
ok( -e "$a_ram.inx", 'Preloads .inx on table_info call' );
# Check excluded table with explicit use_ramdisk => 0
my $e_info = $adb_g1->table_info('catalog_excluded');
my $e_ram = $adb_g1->ramdisk_path('catalog_excluded');
is( $e_info->{use_ramdisk}, 0, 'Table preserves explicit use_ramdisk => 0 override' );
ok( !-e "$e_ram.inx", 'Excluded table is NOT copied to RAM-disk' );
# 3. Open with global cfg => { use_ramdisk => 2 } (Full Table Acceleration)
my $adb_g2 = AmberDB->new(
database => 'catalog',
cfg => { use_ramdisk => 2 },
path => { dbase_dir => $g_tmp, ramdisk_dir => $g_ram }
);
my $b2_path = $adb_g2->table_path('catalog_books');
ok( -e "$b_ram.db", 'Global use_ramdisk => 2 preloads .db to RAM-disk on table_path' );
ok( -e "$b_ram.inx", 'Global use_ramdisk => 2 keeps .inx on RAM-disk' );
is( ($adb_g2->read_id('catalog_books', 1))[1], 'Book One', 'read_id reads from RAM-disk in mode 2' );
# Insert new record under global mode 2
$adb_g2->insert_id( 'catalog_books', 2, 'Book Two' );
is( ($adb_g2->read_id('catalog_books', 2))[1], 'Book Two', 'Newly inserted record readable' );
ok( -e "$b_ram.db", 'RAM-disk .db persists with new record' );
ok( -e "$b_path.db", 'Permanent disk .db dual-written synchronously' );
};
subtest 'Unmounted RAM-disk strips use_ramdisk from table_info and table_attr' => sub {
plan tests => 6;
my $u_tmp = tempdir( CLEANUP => 1 );
xt/amberdb_ramdisk.t view on Meta::CPAN
# 1. From schema file
my $file_info = $adb_unmounted->table_info('books_rd');
ok( !exists $file_info->{use_ramdisk}, 'use_ramdisk stripped from schema file when RAM-disk is unmounted' );
# 2. From table_attr
$adb_unmounted->table_attr( 'dynamic_tbl', use_ramdisk => 1 );
my $attr_info = $adb_unmounted->table_info('dynamic_tbl');
ok( !exists $attr_info->{use_ramdisk}, 'use_ramdisk stripped from table_info after table_attr when unmounted' );
is( $adb_unmounted->table_attr( 'dynamic_tbl', 'use_ramdisk' ), undef, 'table_attr getter returns undef when unmounted' );
# 3. From global config inheritance
my $glob_info = $adb_unmounted->table_info('unconfigured_tbl');
ok( !exists $glob_info->{use_ramdisk}, 'Global use_ramdisk is NOT inherited when unmounted' );
# 4. Now simulate mounted RAM-disk
local $ENV{AMBERDB_TEST_RAMDISK} = 1;
my $adb_mounted = AmberDB->new(
database => 'unmount_test',
cfg => { use_ramdisk => 1 },
path => { dbase_dir => $u_tmp, ramdisk_dir => $u_ram }
);
my $m_file_info = $adb_mounted->table_info('books_rd');
xt/amberdb_ramdisk.t view on Meta::CPAN
};
subtest 'use_ramdisk => 3 (Volatile RAM-Disk Tier 3 & TTL)' => sub {
my $tmp = File::Temp->newdir( CLEANUP => 1 );
my $t3_mount = File::Temp->newdir( CLEANUP => 1 );
my $t3_ram = File::Spec->catdir( $t3_mount, 'amberdb_session_db' );
make_path($t3_ram);
local $ENV{AMBERDB_TEST_RAMDISK} = 1;
# 1. Global use_ramdisk => 3 rejection/fallback to 0
my $adb_global = AmberDB->new(
database => 'session_db',
cfg => { use_ramdisk => 3 },
path => { dbase_dir => $tmp, ramdisk_dir => $t3_ram }
);
is( $adb_global->config('use_ramdisk'), 0, 'Global use_ramdisk => 3 in constructor falls back to 0' );
$adb_global->config( use_ramdisk => 3 );
is( $adb_global->config('use_ramdisk'), 0, 'Global config(use_ramdisk => 3) falls back to 0' );
my $inh_info = $adb_global->table_info('unspec_table');
is( $inh_info->{use_ramdisk}, 0, 'Unspecified table inherits 0, not 3' );
# 2. Per-table use_ramdisk => 3 configuration and schema stripping
my $adb = AmberDB->new(
database => 'session_db',
path => { dbase_dir => $tmp, ramdisk_dir => $t3_ram }
);
my $ramdisk_dir = $adb->ramdisk_dir();
$adb->table_attr( 'session_store',