FFmpegfs Fuse Multi Media Filesystem 2.16
cache.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 2017-2024 Norbert Schlia (nschlia@oblivion-software.de)
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 * On Debian systems, the complete text of the GNU General Public License
19 * Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
20 */
21
32#include "cache.h"
33#include "cache_entry.h"
34#include "ffmpegfs.h"
35#include "logging.h"
36
37#include <vector>
38#include <cassert>
39#include <sqlite3.h>
40
41#ifndef HAVE_SQLITE_ERRSTR
42#define sqlite3_errstr(rc) ""
43#endif // HAVE_SQLITE_ERRSTR
44
45#define STRINGIFY(x) #x
46#define TOSTRING(x) STRINGIFY(x)
48Cache::sqlite_t::sqlite_t(const std::string & filename, int flags, const char *zVfs)
49 : m_ret(SQLITE_OK)
50 , m_filename(filename)
51 , m_select_stmt(nullptr)
52 , m_insert_stmt(nullptr)
53 , m_delete_stmt(nullptr)
54{
55 m_ret = sqlite3_open_v2(m_filename.c_str(), &m_db_handle, flags, zVfs);
56}
57
59{
60 if (m_db_handle != nullptr)
61 {
62#ifdef HAVE_SQLITE_CACHEFLUSH
63 flush_index();
64#endif // HAVE_SQLITE_CACHEFLUSH
65
66 sqlite3_finalize(m_select_stmt);
67 sqlite3_finalize(m_insert_stmt);
68 sqlite3_finalize(m_delete_stmt);
69
70 sqlite3_close(m_db_handle);
71 }
72 sqlite3_shutdown();
73}
74
76{
77 //
78 // Table name
79 //
80 "cache_entry",
81 //
82 // Primary key
83 //
84 "PRIMARY KEY(`filename`,`desttype`)"
85};
86
88{
89 //
90 // Primary key: filename + desttype
91 //
92 { "filename", "TEXT NOT NULL" },
93 { "desttype", "CHAR ( 10 ) NOT NULL" },
94 //
95 // Encoding parameters
96 //
97 { "enable_ismv", "BOOLEAN NOT NULL" },
98 { "audiobitrate", "UNSIGNED INT NOT NULL" },
99 { "audiosamplerate", "UNSIGNED INT NOT NULL" },
100 { "videobitrate", "UNSIGNED INT NOT NULL" },
101 { "videowidth", "UNSIGNED INT NOT NULL" },
102 { "videoheight", "UNSIGNED INT NOT NULL" },
103 { "deinterlace", "BOOLEAN NOT NULL" },
104 //
105 // Encoding results
106 //
107 { "duration", "UNSIGNED BIG INT NOT NULL" },
108 { "predicted_filesize", "UNSIGNED BIG INT NOT NULL" },
109 { "encoded_filesize", "UNSIGNED BIG INT NOT NULL" },
110 { "video_frame_count", "UNSIGNED BIG INT NOT NULL" },
111 { "segment_count", "UNSIGNED BIG INT NOT NULL" },
112 { "finished", "INT NOT NULL" },
113 { "error", "BOOLEAN NOT NULL" },
114 { "errno", "INT NOT NULL" },
115 { "averror", "INT NOT NULL" },
116 { "creation_time", "DATETIME NOT NULL" },
117 { "access_time", "DATETIME NOT NULL" },
118 { "file_time", "DATETIME NOT NULL" },
119 { "file_size", "UNSIGNED BIG INT NOT NULL" }
120};
121
123{
124 //
125 // Table name
126 //
127 "version",
128 //
129 nullptr
130};
131
133{
134 { "db_version_major", "INTEGER NOT NULL" },
135 { "db_version_minor", "INTEGER NOT NULL" }
136};
137
139{
140}
141
143{
144 // Clean up memory
145 for (auto& [key, value] : m_cache)
146 {
147 value->destroy();
148 }
149
150 m_cache.clear();
151
152 close_index();
153}
154
156{
157 int ret;
158 const char * sql;
159
160 sql = "INSERT OR REPLACE INTO cache_entry\n"
161 "(filename, desttype, enable_ismv, audiobitrate, audiosamplerate, videobitrate, videowidth, videoheight, deinterlace, duration, predicted_filesize, encoded_filesize, video_frame_count, segment_count, finished, error, errno, averror, creation_time, access_time, file_time, file_size) VALUES\n"
162 "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), ?);\n";
163
164 if (SQLITE_OK != (ret = sqlite3_prepare_v2(*m_cacheidx_db, sql, -1, &m_cacheidx_db->m_insert_stmt, nullptr)))
165 {
166 Logging::error(m_cacheidx_db->filename(), "Failed to prepare insert: (%1) %2\n%3", ret, sqlite3_errmsg(*m_cacheidx_db), sql);
167 return false;
168 }
169
170 sql = "SELECT desttype, enable_ismv, audiobitrate, audiosamplerate, videobitrate, videowidth, videoheight, deinterlace, duration, predicted_filesize, encoded_filesize, video_frame_count, segment_count, finished, error, errno, averror, strftime('%s', creation_time), strftime('%s', access_time), strftime('%s', file_time), file_size FROM cache_entry WHERE filename = ? AND desttype = ?;\n";
171
172 if (SQLITE_OK != (ret = sqlite3_prepare_v2(*m_cacheidx_db, sql, -1, &m_cacheidx_db->m_select_stmt, nullptr)))
173 {
174 Logging::error(m_cacheidx_db->filename(), "Failed to prepare select: (%1) %2\n%3", ret, sqlite3_errmsg(*m_cacheidx_db), sql);
175 return false;
176 }
177
178 sql = "DELETE FROM cache_entry WHERE filename = ? AND desttype = ?;\n";
179
180 if (SQLITE_OK != (ret = sqlite3_prepare_v2(*m_cacheidx_db, sql, -1, &m_cacheidx_db->m_delete_stmt, nullptr)))
181 {
182 Logging::error(m_cacheidx_db->filename(), "Failed to prepare delete: (%1) %2\n%3", ret, sqlite3_errmsg(*m_cacheidx_db), sql);
183 return false;
184 }
185
186 return true;
187}
188
189bool Cache::table_exists(const char *table)
190{
191 std::string sql;
192 sqlite3_stmt * stmt = nullptr;
193 int results = 0;
194 int ret;
195
196 sql = "SELECT Count(*) FROM sqlite_master WHERE type='table' AND name='";
197 sql += table;
198 sql += "'";
199
200 if (SQLITE_OK != (ret = sqlite3_prepare_v2(*m_cacheidx_db, sql.c_str(), -1, &stmt, nullptr)))
201 {
202 Logging::error(m_cacheidx_db->filename(), "Failed to prepare statement for table_exists: (%1) %2\n%3", ret, sqlite3_errmsg(*m_cacheidx_db), sql.c_str());
203 return false;
204 }
205
206 ret = sqlite3_step(stmt);
207
208 if (ret == SQLITE_ROW)
209 {
210 results = sqlite3_column_int(stmt, 0);
211 }
212
213 sqlite3_finalize(stmt);
214
215 return (results == 1);
216}
217
218bool Cache::column_exists(const char *table, const char *column)
219{
220 std::string sql;
221 sqlite3_stmt * stmt = nullptr;
222 int results = 0;
223 int ret;
224
225 sql = "SELECT COUNT(*) AS CNTREC FROM pragma_table_info('";
226 sql += table;
227 sql += "') WHERE name='";
228 sql += column;
229 sql += "';";
230
231 if (SQLITE_OK != (ret = sqlite3_prepare_v2(*m_cacheidx_db, sql.c_str(), -1, &stmt, nullptr)))
232 {
233 Logging::error(m_cacheidx_db->filename(), "Failed to prepare statement for table_exists: (%1) %2\n%3", ret, sqlite3_errmsg(*m_cacheidx_db), sql.c_str());
234 return false;
235 }
236
237 ret = sqlite3_step(stmt);
238
239 if (ret == SQLITE_ROW)
240 {
241 results = sqlite3_column_int(stmt, 0);
242 }
243
244 sqlite3_finalize(stmt);
245
246 return (results == 1);
247}
248
249bool Cache::check_min_version(int *db_version_major, int *db_version_minor)
250{
251 std::string sql;
252 sqlite3_stmt * stmt = nullptr;
253 int ret;
254
255 sql = "SELECT db_version_major, db_version_minor FROM version;";
256
257 if (SQLITE_OK != (ret = sqlite3_prepare_v2(*m_cacheidx_db, sql.c_str(), -1, &stmt, nullptr)))
258 {
259 Logging::error(m_cacheidx_db->filename(), "Failed to prepare statement for check_min_version: (%1) %2\n%3", ret, sqlite3_errmsg(*m_cacheidx_db), sql.c_str());
260 return false;
261 }
262
263 ret = sqlite3_step(stmt);
264
265 if (ret == SQLITE_ROW)
266 {
267 *db_version_major = sqlite3_column_int(stmt, 0);
268 *db_version_minor = sqlite3_column_int(stmt, 1);
269 }
270
271 sqlite3_finalize(stmt);
272
273 return (cmp_version(*db_version_major, *db_version_minor, DB_MIN_VERSION_MAJOR, DB_MIN_VERSION_MINOR) >= 0);
274}
275
276int Cache::cmp_version(int version_major_l, int version_minor_l, int version_major_r, int version_minor_r)
277{
278 if (version_major_l > version_major_r)
279 {
280 return 1;
281 }
282 if (version_major_l < version_major_r)
283 {
284 return -1;
285 }
286
287 // version_major_l == version_major_r
288
289 if (version_minor_l > version_minor_r)
290 {
291 return 1;
292 }
293 if (version_minor_l < version_minor_r)
294 {
295 return -1;
296 }
297
298 // version_minor_l == version_minor_r
299
300 return 0;
301}
302
304{
305 char *errmsg = nullptr;
306 const char * sql;
307 int ret;
308
309 sql = "BEGIN TRANSACTION;";
310 if (SQLITE_OK != (ret = sqlite3_exec(*m_cacheidx_db, sql, nullptr, nullptr, &errmsg)))
311 {
312 Logging::error(m_cacheidx_db->filename(), "SQLite3 begin transaction failed: (%1) %2\n%3", ret, errmsg, sql);
313 sqlite3_free(errmsg);
314 return false;
315 }
316 return true;
317}
318
320{
321 char *errmsg = nullptr;
322 const char * sql;
323 int ret;
324
325 sql = "END TRANSACTION;";
326 if (SQLITE_OK != (ret = sqlite3_exec(*m_cacheidx_db, sql, nullptr, nullptr, &errmsg)))
327 {
328 Logging::error(m_cacheidx_db->filename(), "SQLite3 end transaction failed: (%1) %2\n%3", ret, errmsg, sql);
329 sqlite3_free(errmsg);
330 return false;
331 }
332 return true;
333}
334
336{
337 char *errmsg = nullptr;
338 const char * sql;
339 int ret;
340
341 sql = "ROLLBACK;";
342 if (SQLITE_OK != (ret = sqlite3_exec(*m_cacheidx_db, sql, nullptr, nullptr, &errmsg)))
343 {
344 Logging::error(m_cacheidx_db->filename(), "SQLite3 rollback transaction failed: (%1) %2\n%3", ret, errmsg, sql);
345 sqlite3_free(errmsg);
346 return false;
347 }
348 return true;
349}
350
352{
353 char *errmsg = nullptr;
354 std::string sql;
355 int ret;
356
357 sql = "CREATE TABLE `";
358 sql += table->name;
359 sql += "` (\n";
360
361 int i = 0;
362 for (const TABLE_COLUMNS & col : columns)
363 {
364 if (i++)
365 {
366 sql += ",\n";
367 }
368 sql += "`";
369 sql += col.name;
370 sql += "` ";
371 sql += col.type;
372 }
373
374 if (table->primary_key != nullptr)
375 {
376 sql += ",\n";
377 sql += table->primary_key;
378 }
379 sql += "\n";
380 sql += ");\n";
381
382 if (SQLITE_OK != (ret = sqlite3_exec(*m_cacheidx_db, sql.c_str(), nullptr, nullptr, &errmsg)))
383 {
384 Logging::error(m_cacheidx_db->filename(), "SQLite3 exec error: (%1) %2\n%3", ret, errmsg, sql.c_str());
385 sqlite3_free(errmsg);
386 return false;
387 }
388 return true;
389}
390
391bool Cache::upgrade_db(int *db_version_major, int *db_version_minor)
392{
393 if (!column_exists("cache_entry", "video_frame_count"))
394 {
395 // If video_frame_count is missing, this db is definetly old
396
397 {
398 char *errmsg = nullptr;
399 std::string sql;
400 int ret;
401
402 Logging::debug(m_cacheidx_db->filename(), "Adding `video_frame_count` column.");
403
404 // Add `video_frame_count` UNSIGNED BIG INT NOT NULL DEFAULT 0
405 sql = "ALTER TABLE `";
407 sql += "` ADD COLUMN `video_frame_count` UNSIGNED BIG INT NOT NULL DEFAULT 0;\n";
408 if (SQLITE_OK != (ret = sqlite3_exec(*m_cacheidx_db, sql.c_str(), nullptr, nullptr, &errmsg)))
409 {
410 Logging::error(m_cacheidx_db->filename(), "SQLite3 exec error adding column `video_frame_count`: (%1) %2\n%3", ret, errmsg, sql.c_str());
411 sqlite3_free(errmsg);
412 return false;
413 }
414
415 Logging::debug(m_cacheidx_db->filename(), "Altering `finished` from BOOLEAN to INT.");
416 }
417
418 {
419 char *errmsg = nullptr;
420 std::string sql;
421 int ret;
422
423 //ALTER `finished` from BOOLEAN to INT NOT NULL
424 // sqlite can't do that for us, we must...
425 //
426 // 1. Rename `cache_entry` to `cache_entry_old`
427 // 2. Create new table `cache_entry` with new structure
428 // 3. Copy all data from `cache_entry_old` to `cache_entry`, converting old to new column
429 // 4. Delete `cache_entry_old`
430
431 sql = "PRAGMA foreign_keys=off;\n";
432 if (SQLITE_OK != (ret = sqlite3_exec(*m_cacheidx_db, sql.c_str(), nullptr, nullptr, &errmsg)))
433 {
434 Logging::error(m_cacheidx_db->filename(), "SQLite3 exec error: (%1) %2\n%3", ret, errmsg, sql.c_str());
435 sqlite3_free(errmsg);
436 return false;
437 }
438 }
439
440 // Step 1
441 {
442 char *errmsg = nullptr;
443 std::string sql;
444 int ret;
445
446 sql = "ALTER TABLE `";
448 sql += "` RENAME TO `";
450 sql += "_old`;\n";
451 if (SQLITE_OK != (ret = sqlite3_exec(*m_cacheidx_db, sql.c_str(), nullptr, nullptr, &errmsg)))
452 {
453 Logging::error(m_cacheidx_db->filename(), "SQLite3 exec error: (%1) %2\n%3", ret, errmsg, sql.c_str());
454 sqlite3_free(errmsg);
455 return false;
456 }
457 }
458
459 // Step 2
461 {
462 Logging::error(m_cacheidx_db->filename(), "SQLite3 exec error creating 'cache_entry' table.");
463 return false;
464 }
465
466 // Step 3
467 {
468 char *errmsg = nullptr;
469 std::string sql;
470 std::string columns;
471 int ret;
472
473 for (const TABLE_COLUMNS & col : m_columns_cache_entry)
474 {
475 if (!columns.empty())
476 {
477 columns += ",";
478 }
479 columns += "`";
480 columns += col.name;
481 columns += "`";
482 }
483
484 sql = "INSERT INTO `";
486 sql += "` (";
487 sql += columns;
488 sql += ")\nSELECT ";
489 sql += columns;
490 sql += " FROM `";
492 sql += "_old`;";
493
494 if (SQLITE_OK != (ret = sqlite3_exec(*m_cacheidx_db, sql.c_str(), nullptr, nullptr, &errmsg)))
495 {
496 Logging::error(m_cacheidx_db->filename(), "SQLite3 exec error: (%1) %2\n%3", ret, errmsg, sql.c_str());
497 sqlite3_free(errmsg);
498 return false;
499 }
500 }
501
502 {
503 char *errmsg = nullptr;
504 std::string sql;
505 int ret;
506
507 // Old 0 is RESULTCODE::NONE (0)
508 // Old 1 is RESULTCODE::FINISHED (2)
509 sql = "UPDATE `";
511 sql += "`\n";
512 sql += "SET `finished` = 3\n";
513 sql += "WHERE `finished` = 1\n";
514 if (SQLITE_OK != (ret = sqlite3_exec(*m_cacheidx_db, sql.c_str(), nullptr, nullptr, &errmsg)))
515 {
516 Logging::error(m_cacheidx_db->filename(), "SQLite3 exec error updating column `finished`: (%1) %2\n%3", ret, errmsg, sql.c_str());
517 sqlite3_free(errmsg);
518 return false;
519 }
520 }
521
522 // Step 4
523 {
524 char *errmsg = nullptr;
525 std::string sql;
526 int ret;
527
528 sql = "DROP TABLE `cache_entry_old`";
529 if (SQLITE_OK != (ret = sqlite3_exec(*m_cacheidx_db, sql.c_str(), nullptr, nullptr, &errmsg)))
530 {
531 Logging::error(m_cacheidx_db->filename(), "SQLite3 exec error adding column `video_frame_count`: (%1) %2\n%3", ret, errmsg, sql.c_str());
532 sqlite3_free(errmsg);
533 return false;
534 }
535
536 sql = "PRAGMA foreign_keys=on;\n";
537 if (SQLITE_OK != (ret = sqlite3_exec(*m_cacheidx_db, sql.c_str(), nullptr, nullptr, &errmsg)))
538 {
539 Logging::error(m_cacheidx_db->filename(), "SQLite3 exec error: (%1) %2\n%3", ret, errmsg, sql.c_str());
540 sqlite3_free(errmsg);
541 return false;
542 }
543 }
544 }
545
546 if (!column_exists("cache_entry", "duration"))
547 {
548 char *errmsg = nullptr;
549 std::string sql;
550 int ret;
551
552 Logging::debug(m_cacheidx_db->filename(), "Adding `duration` column.");
553
554 // Add `duration` UNSIGNED BIG INT NOT NULL DEFAULT 0
555 sql = "ALTER TABLE `";
557 sql += "` ADD COLUMN `duration` UNSIGNED BIG INT NOT NULL DEFAULT 0;\n";
558 if (SQLITE_OK != (ret = sqlite3_exec(*m_cacheidx_db, sql.c_str(), nullptr, nullptr, &errmsg)))
559 {
560 Logging::error(m_cacheidx_db->filename(), "SQLite3 exec error adding column `duration`: (%1) %2\n%3", ret, errmsg, sql.c_str());
561 sqlite3_free(errmsg);
562 return false;
563 }
564 }
565
566 if (!column_exists("cache_entry", "segment_count"))
567 {
568 char *errmsg = nullptr;
569 std::string sql;
570 int ret;
571
572 Logging::debug(m_cacheidx_db->filename(), "Adding `segment_count` column.");
573
574 // Add `segment_count` UNSIGNED BIG INT NOT NULL DEFAULT 0
575 sql = "ALTER TABLE `";
577 sql += "` ADD COLUMN `segment_count` UNSIGNED BIG INT NOT NULL DEFAULT 0;\n";
578 if (SQLITE_OK != (ret = sqlite3_exec(*m_cacheidx_db, sql.c_str(), nullptr, nullptr, &errmsg)))
579 {
580 Logging::error(m_cacheidx_db->filename(), "SQLite3 exec error adding column `segment_count`: (%1) %2\n%3", ret, errmsg, sql.c_str());
581 sqlite3_free(errmsg);
582 return false;
583 }
584 }
585
586 // Update DB version
587 Logging::debug(m_cacheidx_db->filename(), "Updating version table to V%1.%2.", DB_VERSION_MAJOR, DB_VERSION_MINOR);
588
589 {
590 char *errmsg = nullptr;
591 const char * sql;
592 int ret;
593
594 sql = "UPDATE `version` SET db_version_major = " TOSTRING(DB_VERSION_MAJOR) ", db_version_minor = " TOSTRING(DB_VERSION_MINOR) ";\n";
595 if (SQLITE_OK != (ret = sqlite3_exec(*m_cacheidx_db, sql, nullptr, nullptr, &errmsg)))
596 {
597 Logging::error(m_cacheidx_db->filename(), "SQLite3 exec error: (%1) %2\n%3", ret, errmsg, sql);
598 sqlite3_free(errmsg);
599 return false;
600 }
601
602 *db_version_major = DB_VERSION_MAJOR;
603 *db_version_minor = DB_VERSION_MINOR;
604 }
605
606 Logging::info(m_cacheidx_db->filename(), "Database successfully upgraded to V%1.%2.", *db_version_major, *db_version_minor);
607
608 return true;
609}
610
612{
613 bool success = true;
614
615 try
616 {
617 std::string filename;
618 char *errmsg = nullptr;
619 int ret;
620 bool new_database = false;
621 bool need_upate = false;
622
623 transcoder_cache_path(&filename);
624
625 if (mktree(filename, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) && errno != EEXIST)
626 {
627 Logging::error(filename, "Error creating cache directory: (%1) %2\n%3", errno, strerror(errno), m_cacheidx_db->filename().c_str());
628 throw false;
629 }
630
631 append_filename(&filename, "cacheidx.sqlite");
632
633 // initialise engine
634 if (SQLITE_OK != (ret = sqlite3_initialize()))
635 {
636 Logging::error(filename, "Failed to initialise SQLite3 library: (%1) %2", ret, sqlite3_errstr(ret));
637 throw false;
638 }
639
640 // open connection to a DB
641 m_cacheidx_db = std::make_unique<sqlite_t>(filename, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_SHAREDCACHE);
642
643 if (m_cacheidx_db == nullptr)
644 {
645 Logging::error(filename, "Out of memory.");
646 throw false;
647 }
648
649 if (SQLITE_OK != (ret = m_cacheidx_db->ret()))
650 {
651 Logging::error(m_cacheidx_db->filename(), "Failed to initialise SQLite3 connection: (%1) %2", ret, sqlite3_errmsg(*m_cacheidx_db));
652 throw false;
653 }
654
655 if (SQLITE_OK != (ret = sqlite3_busy_timeout(*m_cacheidx_db, 1000)))
656 {
657 Logging::error(m_cacheidx_db->filename(), "Failed to set SQLite3 busy timeout: (%1) %2", ret, sqlite3_errmsg(*m_cacheidx_db));
658 throw false;
659 }
660
661 // Beginning with version 3.7.0 (2010-07-21), a new "Write-Ahead Log" option
662 // We support Sqlite from 3.7.13 anyway
663 if (SQLITE_OK != (ret = sqlite3_exec(*m_cacheidx_db, "pragma journal_mode = WAL", nullptr, nullptr, nullptr)))
664 {
665 Logging::error(m_cacheidx_db->filename(), "Failed to set SQLite3 WAL mode: (%1) %2", ret, sqlite3_errmsg(*m_cacheidx_db));
666 throw false;
667 }
668
669 // Very strange: Compare operations with =, > etc. are case sensitive, while LIKE by default ignores upper/lowercase.
670 // Produces strange results when reading from a Samba drive and different cases are used...
671 if (SQLITE_OK != (ret = sqlite3_exec(*m_cacheidx_db, "PRAGMA case_sensitive_like = 1;", nullptr, nullptr, nullptr)))
672 {
673 Logging::error(m_cacheidx_db->filename(), "Failed to set SQLite3 case_sensitive_like = 1: (%1) %2", ret, sqlite3_errmsg(*m_cacheidx_db));
674 throw false;
675 }
676
677 // Make sure the next changes are either all successfull or rolled back
678 if (!begin_transaction())
679 {
680 throw false;
681 }
682
683 // Check if we got a new, empty database and create necessary tables
684
685 // Create cache_entry table if not already existing
686 if (!table_exists("cache_entry"))
687 {
688 Logging::debug(m_cacheidx_db->filename(), "Creating 'cache_entry' table in database.");
689
691 {
692 Logging::error(m_cacheidx_db->filename(), "SQLite3 exec error creating 'cache_entry' table: (%1) %2", ret, errmsg);
693 throw false;
694 }
695
696 new_database = true; // Created a new database
697 }
698
699 // If version table does not exist add it
700 if (!table_exists("version"))
701 {
702 const char * sql;
703
704 Logging::debug(m_cacheidx_db->filename(), "Creating 'version' table in database.");
705
707 {
708 Logging::error(m_cacheidx_db->filename(), "SQLite3 exec error creating 'cache_entry' table: (%1) %2", ret, errmsg);
709 throw false;
710 }
711
712 sql = "INSERT INTO `version` (db_version_major, db_version_minor) VALUES (" TOSTRING(DB_VERSION_MAJOR) ", " TOSTRING(DB_VERSION_MINOR) ");\n";
713 if (SQLITE_OK != (ret = sqlite3_exec(*m_cacheidx_db, sql, nullptr, nullptr, &errmsg)))
714 {
715 Logging::error(m_cacheidx_db->filename(), "SQLite3 exec error: (%1) %2\n%3", ret, errmsg, sql);
716 sqlite3_free(errmsg);
717 throw false;
718 }
719
720 if (!new_database)
721 {
722 // Added version only, old database, need upgrade
723 need_upate = true;
724 }
725 }
726
727 // Check if database needs a structure upgrade
728 int db_version_major = DB_BASE_VERSION_MAJOR; // Old database contains no version table. This is the version of this database.
729 int db_version_minor = DB_BASE_VERSION_MINOR;
730 if (need_upate || !check_min_version(&db_version_major, &db_version_minor))
731 {
732 // No version table found, or minimum version too low, do an upgrade.
733 Logging::warning(m_cacheidx_db->filename(), "Database version is %1.%2, but a least %3.%4 required. Upgrading database now.", db_version_major, db_version_minor, DB_MIN_VERSION_MAJOR, DB_MIN_VERSION_MINOR);
734
735 if (!upgrade_db(&db_version_major, &db_version_minor))
736 {
737 throw false;
738 }
739 }
740
741 if (!end_transaction())
742 {
743 throw false;
744 }
745
746#ifdef HAVE_SQLITE_CACHEFLUSH
747 if (!m_cacheidx_db->flush_index())
748 {
749 throw false;
750 }
751#endif // HAVE_SQLITE_CACHEFLUSH
752
753 // prepare the statements
754 if (!prepare_stmts())
755 {
756 throw false;
757 }
758 }
759 catch (bool _success)
760 {
761 success = _success;
762 }
763
764 return success;
765}
766
767#ifdef HAVE_SQLITE_CACHEFLUSH
768bool Cache::sqlite_t::flush_index()
769{
770 if (m_db_handle != nullptr)
771 {
772 int ret;
773
774 // Flush cache to disk
775 if (SQLITE_OK != (ret = sqlite3_db_cacheflush(m_db_handle)))
776 {
777 Logging::error(m_filename, "SQLite3 cache flush error: (%1) %2", ret, sqlite3_errstr(ret));
778 return false;
779 }
780 }
781 return true;
782}
783#endif // HAVE_SQLITE_CACHEFLUSH
784
786{
787 bool success = true;
788
789 //cache_info->m_enable_ismv = 0;
790 cache_info->m_audiobitrate = 0;
791 cache_info->m_audiosamplerate = 0;
792 cache_info->m_videobitrate = 0;
793 cache_info->m_videowidth = 0;
794 cache_info->m_videoheight = 0;
795 cache_info->m_deinterlace = false;
796 cache_info->m_duration = 0;
797 cache_info->m_predicted_filesize = 0;
798 cache_info->m_encoded_filesize = 0;
799 cache_info->m_video_frame_count = 0;
800 cache_info->m_segment_count = 0;
801 cache_info->m_result = RESULTCODE::NONE;
802 cache_info->m_error = false;
803 cache_info->m_errno = 0;
804 cache_info->m_averror = 0;
805 cache_info->m_creation_time = 0;
806 cache_info->m_access_time = 0;
807 cache_info->m_file_time = 0;
808 cache_info->m_file_size = 0;
809
810 if (m_cacheidx_db->m_select_stmt == nullptr)
811 {
812 Logging::error(m_cacheidx_db->filename(), "SQLite3 select statement not open.");
813 return false;
814 }
815
816 std::lock_guard<std::recursive_mutex> lock_mutex(m_mutex);
817
818 try
819 {
820 int ret;
821
822 assert(sqlite3_bind_parameter_count(m_cacheidx_db->m_select_stmt) == 2);
823
824 if (SQLITE_OK != (ret = sqlite3_bind_text(m_cacheidx_db->m_select_stmt, 1, cache_info->m_destfile.c_str(), -1, nullptr)))
825 {
826 Logging::error(m_cacheidx_db->filename(), "SQLite3 select error binding 'filename': (%1) %2", ret, sqlite3_errstr(ret));
827 throw false;
828 }
829
830 if (SQLITE_OK != (ret = sqlite3_bind_text(m_cacheidx_db->m_select_stmt, 2, cache_info->m_desttype.data(), -1, nullptr)))
831 {
832 Logging::error(m_cacheidx_db->filename(), "SQLite3 select error binding 'desttype': (%1) %2", ret, sqlite3_errstr(ret));
833 throw false;
834 }
835
836 ret = sqlite3_step(m_cacheidx_db->m_select_stmt);
837
838 if (ret == SQLITE_ROW)
839 {
840 const char *text = reinterpret_cast<const char *>(sqlite3_column_text(m_cacheidx_db->m_select_stmt, 0));
841 if (text != nullptr)
842 {
843 cache_info->m_desttype[0] = '\0';
844 strncat(cache_info->m_desttype.data(), text, cache_info->m_desttype.size() - 1);
845 }
846 //cache_info->m_enable_ismv = sqlite3_column_int(m_cacheidx_db->m_cacheidx_select_stmt, 1);
847 cache_info->m_audiobitrate = sqlite3_column_int(m_cacheidx_db->m_select_stmt, 2);
848 cache_info->m_audiosamplerate = sqlite3_column_int(m_cacheidx_db->m_select_stmt, 3);
849 cache_info->m_videobitrate = sqlite3_column_int(m_cacheidx_db->m_select_stmt, 4);
850 cache_info->m_videowidth = sqlite3_column_int(m_cacheidx_db->m_select_stmt, 5);
851 cache_info->m_videoheight = sqlite3_column_int(m_cacheidx_db->m_select_stmt, 6);
852 cache_info->m_deinterlace = sqlite3_column_int(m_cacheidx_db->m_select_stmt, 7);
853 cache_info->m_duration = sqlite3_column_int64(m_cacheidx_db->m_select_stmt, 8);
854 cache_info->m_predicted_filesize = static_cast<size_t>(sqlite3_column_int64(m_cacheidx_db->m_select_stmt, 9));
855 cache_info->m_encoded_filesize = static_cast<size_t>(sqlite3_column_int64(m_cacheidx_db->m_select_stmt, 10));
856 cache_info->m_video_frame_count = static_cast<uint32_t>(sqlite3_column_int(m_cacheidx_db->m_select_stmt, 11));
857 cache_info->m_segment_count = static_cast<uint32_t>(sqlite3_column_int(m_cacheidx_db->m_select_stmt, 12));
858 cache_info->m_result = static_cast<RESULTCODE>(sqlite3_column_int(m_cacheidx_db->m_select_stmt, 13));
859 cache_info->m_error = sqlite3_column_int(m_cacheidx_db->m_select_stmt, 14);
860 cache_info->m_errno = sqlite3_column_int(m_cacheidx_db->m_select_stmt, 15);
861 cache_info->m_averror = sqlite3_column_int(m_cacheidx_db->m_select_stmt, 16);
862 cache_info->m_creation_time = static_cast<time_t>(sqlite3_column_int64(m_cacheidx_db->m_select_stmt, 17));
863 cache_info->m_access_time = static_cast<time_t>(sqlite3_column_int64(m_cacheidx_db->m_select_stmt, 18));
864 cache_info->m_file_time = static_cast<time_t>(sqlite3_column_int64(m_cacheidx_db->m_select_stmt, 19));
865 cache_info->m_file_size = static_cast<size_t>(sqlite3_column_int64(m_cacheidx_db->m_select_stmt, 20));
866 }
867 else if (ret != SQLITE_DONE)
868 {
869 Logging::error(m_cacheidx_db->filename(), "Sqlite 3 could not step (execute) select statement: (%1) %2", ret, sqlite3_errstr(ret));
870 throw false;
871 }
872 }
873 catch (bool _success)
874 {
875 success = _success;
876 }
877
878 sqlite3_reset(m_cacheidx_db->m_select_stmt);
879
880 if (success)
881 {
882 errno = 0; // sqlite3 sometimes sets errno without any reason, better reset any error
883 }
884
885 return success;
886}
887
888#define SQLBINDTXT(idx, var) \
889 if (SQLITE_OK != (ret = sqlite3_bind_text(m_cacheidx_db->m_insert_stmt, idx, var, -1, nullptr))) \
890{ \
891 Logging::error(m_cacheidx_db->filename(), "SQLite3 select column #%1 error: %2\n%3", idx, ret, sqlite3_errstr(ret)); \
892 throw false; \
893 }
895#define SQLBINDNUM(func, idx, var) \
896 if (SQLITE_OK != (ret = func(m_cacheidx_db->m_insert_stmt, idx, var))) \
897{ \
898 Logging::error(m_cacheidx_db->filename(), "SQLite3 select column #%1 error: %2\n%3", idx, ret, sqlite3_errstr(ret)); \
899 throw false; \
900 }
902bool Cache::write_info(LPCCACHE_INFO cache_info)
903{
904 bool success = true;
905
906 if (m_cacheidx_db->m_insert_stmt == nullptr)
907 {
908 Logging::error(m_cacheidx_db->filename(), "SQLite3 select statement not open.");
909 return false;
911
912 std::lock_guard<std::recursive_mutex> lock_mutex(m_mutex);
913
914 try
915 {
916 int ret;
917 bool enable_ismv_dummy = false;
918
919 assert(sqlite3_bind_parameter_count(m_cacheidx_db->m_insert_stmt) == 22);
920
921 SQLBINDTXT(1, cache_info->m_destfile.c_str());
922 SQLBINDTXT(2, cache_info->m_desttype.data());
923 //SQLBINDNUM(sqlite3_bind_int, 3, cache_info->m_enable_ismv);
924 SQLBINDNUM(sqlite3_bind_int, 3, enable_ismv_dummy);
925 SQLBINDNUM(sqlite3_bind_int64, 4, cache_info->m_audiobitrate);
926 SQLBINDNUM(sqlite3_bind_int, 5, cache_info->m_audiosamplerate);
927 SQLBINDNUM(sqlite3_bind_int64, 6, cache_info->m_videobitrate);
928 SQLBINDNUM(sqlite3_bind_int, 7, static_cast<int>(cache_info->m_videowidth));
929 SQLBINDNUM(sqlite3_bind_int, 8, static_cast<int>(cache_info->m_videoheight));
930 SQLBINDNUM(sqlite3_bind_int, 9, cache_info->m_deinterlace);
931 SQLBINDNUM(sqlite3_bind_int64, 10, static_cast<sqlite3_int64>(cache_info->m_duration));
932 SQLBINDNUM(sqlite3_bind_int64, 11, static_cast<sqlite3_int64>(cache_info->m_predicted_filesize));
933 SQLBINDNUM(sqlite3_bind_int64, 12, static_cast<sqlite3_int64>(cache_info->m_encoded_filesize));
934 SQLBINDNUM(sqlite3_bind_int, 13, static_cast<int32_t>(cache_info->m_video_frame_count));
935 SQLBINDNUM(sqlite3_bind_int, 14, static_cast<int32_t>(cache_info->m_segment_count));
936 SQLBINDNUM(sqlite3_bind_int, 15, static_cast<int32_t>(cache_info->m_result));
937 SQLBINDNUM(sqlite3_bind_int, 16, cache_info->m_error);
938 SQLBINDNUM(sqlite3_bind_int, 17, cache_info->m_errno);
939 SQLBINDNUM(sqlite3_bind_int, 18, cache_info->m_averror);
940 SQLBINDNUM(sqlite3_bind_int64, 19, cache_info->m_creation_time);
941 SQLBINDNUM(sqlite3_bind_int64, 20, cache_info->m_access_time);
942 SQLBINDNUM(sqlite3_bind_int64, 21, cache_info->m_file_time);
943 SQLBINDNUM(sqlite3_bind_int64, 22, static_cast<sqlite3_int64>(cache_info->m_file_size));
944
945 ret = sqlite3_step(m_cacheidx_db->m_insert_stmt);
946
947 if (ret != SQLITE_DONE)
948 {
949 Logging::error(m_cacheidx_db->filename(), "Sqlite 3 could not step (execute) insert statement: (%1) %2", ret, sqlite3_errstr(ret));
950 throw false;
951 }
952 }
953 catch (bool _success)
954 {
955 success = _success;
956 }
957
958 sqlite3_reset(m_cacheidx_db->m_insert_stmt);
959
960 if (success)
961 {
962 errno = 0; // sqlite3 sometimes sets errno without any reason, better reset any error
963 }
964
965 return success;
966}
967
968bool Cache::delete_info(const std::string & filename, const std::string & desttype)
969{
970 bool success = true;
971
972 if (m_cacheidx_db->m_delete_stmt == nullptr)
973 {
974 Logging::error(m_cacheidx_db->filename(), "SQLite3 delete statement not open.");
975 return false;
976 }
977
978 std::lock_guard<std::recursive_mutex> lock_mutex(m_mutex);
979
980 try
981 {
982 int ret;
983
984 assert(sqlite3_bind_parameter_count(m_cacheidx_db->m_delete_stmt) == 2);
985
986 if (SQLITE_OK != (ret = sqlite3_bind_text(m_cacheidx_db->m_delete_stmt, 1, filename.c_str(), -1, nullptr)))
987 {
988 Logging::error(m_cacheidx_db->filename(), "SQLite3 select error binding 'filename': (%1) %2", ret, sqlite3_errstr(ret));
989 throw false;
990 }
991
992 if (SQLITE_OK != (ret = sqlite3_bind_text(m_cacheidx_db->m_delete_stmt, 2, desttype.c_str(), -1, nullptr)))
993 {
994 Logging::error(m_cacheidx_db->filename(), "SQLite3 select error binding 'desttype': (%1) %2", ret, sqlite3_errstr(ret));
995 throw false;
996 }
997
998 ret = sqlite3_step(m_cacheidx_db->m_delete_stmt);
999
1000 if (ret != SQLITE_DONE)
1001 {
1002 Logging::error(m_cacheidx_db->filename(), "Sqlite 3 could not step (execute) delete statement: (%1) %2", ret, sqlite3_errstr(ret));
1003 throw false;
1004 }
1005 }
1006 catch (bool _success)
1007 {
1008 success = _success;
1009 }
1010
1011 sqlite3_reset(m_cacheidx_db->m_delete_stmt);
1012
1013 if (success)
1014 {
1015 errno = 0; // sqlite3 sometimes sets errno without any reason, better reset any error
1016 }
1017
1018 return success;
1019}
1020
1021void Cache::close_index()
1022{
1023 m_cacheidx_db.reset();
1024}
1025
1026Cache_Entry* Cache::create_entry(LPVIRTUALFILE virtualfile, const std::string & desttype)
1027{
1028 //Cache_Entry* cache_entry = new (std::nothrow) Cache_Entry(this, filename);
1029 Cache_Entry* cache_entry = Cache_Entry::create(this, virtualfile);
1030 if (cache_entry == nullptr)
1032 Logging::error(m_cacheidx_db->filename(), "Out of memory creating cache entry.");
1033 return nullptr;
1034 }
1035
1036 m_cache.insert(make_pair(make_pair(virtualfile->m_destfile, desttype), cache_entry));
1037
1038 return cache_entry;
1039}
1040
1041bool Cache::delete_entry(Cache_Entry ** cache_entry, int flags)
1042{
1043 if (*cache_entry == nullptr)
1044 {
1045 return true;
1046 }
1047
1048 bool deleted = false;
1049
1050 if ((*cache_entry)->closeio(flags))
1052 // If CACHE_CLOSE_FREE is set, also free memory
1054 {
1055 m_cache.erase(make_pair((*cache_entry)->m_cache_info.m_destfile, (*cache_entry)->m_cache_info.m_desttype.data()));
1056
1057 deleted = (*cache_entry)->destroy();
1058 *cache_entry = nullptr;
1059 }
1060 }
1061
1062 return deleted;
1063}
1064
1066{
1067 Cache_Entry* cache_entry = nullptr;
1068 cache_t::const_iterator p = m_cache.find(make_pair(virtualfile->m_destfile, params.current_format(virtualfile)->desttype()));
1069 if (p == m_cache.cend())
1070 {
1071 Logging::trace(virtualfile->m_destfile, "Created new transcoder.");
1072 cache_entry = create_entry(virtualfile, params.current_format(virtualfile)->desttype());
1073 }
1074 else
1076 Logging::trace(virtualfile->m_destfile, "Reusing cached transcoder.");
1077 cache_entry = p->second;
1078 }
1079
1080 return cache_entry;
1081}
1082
1083bool Cache::closeio(Cache_Entry **cache_entry, int flags /*= CACHE_CLOSE_NOOPT*/)
1084{
1085 if (*cache_entry == nullptr)
1086 {
1087 return true;
1088 }
1089
1090 bool deleted;
1091
1092 std::string filename((*cache_entry)->filename());
1093 if (delete_entry(cache_entry, flags))
1094 {
1095 Logging::trace(filename, "Freed cache entry.");
1096 deleted = true;
1097 }
1098 else
1099 {
1100 Logging::trace(filename, "Keeping cache entry.");
1101 deleted = false;
1102 }
1103
1104 return deleted;
1105}
1106
1108{
1109 if (params.m_expiry_time <= 0)
1110 {
1111 // There's no limit.
1112 return true;
1113 }
1114
1115 std::vector<cache_key_t> keys;
1116 sqlite3_stmt * stmt;
1117 time_t now = time(nullptr);
1118 std::string sql;
1119
1120 Logging::trace(m_cacheidx_db->filename(), "Pruning expired cache entries older than %1...", format_time(params.m_expiry_time).c_str());
1121
1122 strsprintf(&sql, "SELECT filename, desttype, strftime('%%s', access_time) FROM cache_entry WHERE strftime('%%s', access_time) + %" FFMPEGFS_FORMAT_TIME_T " < %" FFMPEGFS_FORMAT_TIME_T ";\n", params.m_expiry_time, now);
1123
1124 std::lock_guard<std::recursive_mutex> lock_mutex(m_mutex);
1125
1126 sqlite3_prepare(*m_cacheidx_db, sql.c_str(), -1, &stmt, nullptr);
1127
1128 int ret = 0;
1129 while ((ret = sqlite3_step(stmt)) == SQLITE_ROW)
1130 {
1131 const char *filename = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0));
1132 const char *desttype = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1));
1133
1134 keys.emplace_back(filename, desttype);
1135
1136 Logging::trace(filename, "Found %1 old entries.", format_time(now - static_cast<time_t>(sqlite3_column_int64(stmt, 2))).c_str());
1137 }
1138
1139 Logging::trace(m_cacheidx_db->filename(), "%1 expired cache entries found.", keys.size());
1140
1141 if (ret == SQLITE_DONE)
1142 {
1143 for (const auto& [key, value] : keys)
1144 {
1145 Logging::trace(m_cacheidx_db->filename(), "Pruning '%1' - Type: %2", key.c_str(), value.c_str());
1146
1147 cache_t::iterator p = m_cache.find(make_pair(key, value));
1148 if (p != m_cache.end())
1149 {
1150 delete_entry(&p->second, CACHE_CLOSE_DELETE);
1151 }
1152
1153 if (delete_info(key, value))
1154 {
1155 remove_cachefile(key, value);
1156 }
1157 }
1158 }
1159 else
1160 {
1161 Logging::error(m_cacheidx_db->filename(), "Failed to execute select. Return code: %1 Error: %2 SQL: %3", ret, sqlite3_errmsg(*m_cacheidx_db), expanded_sql(stmt).c_str());
1162 }
1163
1164 sqlite3_finalize(stmt);
1165
1166 return true;
1167}
1168
1170{
1172 {
1173 // There's no limit.
1174 return true;
1175 }
1176
1177 std::vector<cache_key_t> keys;
1178 std::vector<size_t> filesizes;
1180 const char * sql;
1181
1182 Logging::trace(m_cacheidx_db->filename(), "Pruning oldest cache entries exceeding %1 cache size...", format_size(params.m_max_cache_size).c_str());
1183
1184 sql = "SELECT filename, desttype, encoded_filesize FROM cache_entry ORDER BY access_time ASC;\n";
1185
1186 std::lock_guard<std::recursive_mutex> lock_mutex(m_mutex);
1187
1188 sqlite3_prepare(*m_cacheidx_db, sql, -1, &stmt, nullptr);
1189
1190 int ret = 0;
1191 size_t total_size = 0;
1192 while((ret = sqlite3_step(stmt)) == SQLITE_ROW)
1193 {
1194 const char *filename = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0));
1195 const char *desttype = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1));
1196 size_t size = static_cast<size_t>(sqlite3_column_int64(stmt, 2));
1197
1198 keys.emplace_back(filename, desttype);
1199 filesizes.push_back(size);
1200 total_size += size;
1201 }
1202
1203 Logging::trace(m_cacheidx_db->filename(), "%1 in cache.", format_size(total_size).c_str());
1204
1205 if (total_size > params.m_max_cache_size)
1206 {
1207 Logging::trace(m_cacheidx_db->filename(), "Pruning %1 of oldest cache entries to limit cache size.", format_size(total_size - params.m_max_cache_size).c_str());
1208 if (ret == SQLITE_DONE)
1209 {
1210 size_t n = 0;
1211 for (const auto& [key, value] : keys)
1212 {
1213 Logging::trace(m_cacheidx_db->filename(), "Pruning: %1 Type: %2", key.c_str(), value.c_str());
1214
1215 cache_t::iterator p = m_cache.find(make_pair(key, value));
1216 if (p != m_cache.end())
1217 {
1218 delete_entry(&p->second, CACHE_CLOSE_DELETE);
1219 }
1220
1221 if (delete_info(key, value))
1222 {
1223 remove_cachefile(key, value);
1224 }
1225
1226 total_size -= filesizes[n++];
1227
1228 if (total_size <= params.m_max_cache_size)
1229 {
1230 break;
1231 }
1232 }
1233
1234 Logging::trace(m_cacheidx_db->filename(), "%1 left in cache.", format_size(total_size).c_str());
1235 }
1236 else
1237 {
1238 Logging::error(m_cacheidx_db->filename(), "Failed to execute select. Return code: %1 Error: %2 SQL: %3", ret, sqlite3_errmsg(*m_cacheidx_db), expanded_sql(stmt).c_str());
1239 }
1240 }
1241
1242 sqlite3_finalize(stmt);
1243
1244 return true;
1245}
1246
1247bool Cache::prune_disk_space(size_t predicted_filesize)
1248{
1249 std::string cachepath;
1250
1251 transcoder_cache_path(&cachepath);
1252
1253 size_t free_bytes = get_disk_free(cachepath);
1254
1255 if (!free_bytes && errno)
1256 {
1257 if (errno == ENOENT)
1258 {
1259 // Cache path does not exist. Strange problem, but not error. Ignore silently.
1260 return true;
1261 }
1262
1263 Logging::error(cachepath, "prune_disk_space() cannot determine free disk space: (%1) %2", errno, strerror(errno));
1264 return false;
1265 }
1266
1267 if (free_bytes < predicted_filesize)
1268 {
1269 Logging::error(cachepath, "prune_disk_space() : Insufficient disk space %1 on cache drive, at least %2 required.", format_size(free_bytes).c_str(), format_size(predicted_filesize).c_str());
1270 errno = ENOSPC;
1271 return false;
1272 }
1273
1274 std::lock_guard<std::recursive_mutex> lock_mutex(m_mutex);
1275
1276 Logging::trace(cachepath, "%1 disk space before prune.", format_size(free_bytes).c_str());
1277 if (free_bytes < params.m_min_diskspace + predicted_filesize)
1278 {
1279 std::vector<cache_key_t> keys;
1280 std::vector<size_t> filesizes;
1281 sqlite3_stmt * stmt;
1282 const char * sql;
1283
1284 sql = "SELECT filename, desttype, encoded_filesize FROM cache_entry ORDER BY access_time ASC;\n";
1285
1286 sqlite3_prepare(*m_cacheidx_db, sql, -1, &stmt, nullptr);
1287
1288 int ret = 0;
1289 while ((ret = sqlite3_step(stmt)) == SQLITE_ROW)
1290 {
1291 const char *filename = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0));
1292 const char *desttype = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1));
1293 size_t size = static_cast<size_t>(sqlite3_column_int64(stmt, 2));
1294
1295 keys.emplace_back(filename, desttype);
1296 filesizes.push_back(size);
1297 }
1298
1299 Logging::trace(cachepath, "Pruning %1 of oldest cache entries to keep disk space above %2 limit...", format_size(params.m_min_diskspace + predicted_filesize - free_bytes).c_str(), format_size(params.m_min_diskspace).c_str());
1300
1301 if (ret == SQLITE_DONE)
1302 {
1303 size_t n = 0;
1304 for (const auto& [key, value] : keys)
1305 {
1306 Logging::trace(cachepath, "Pruning: %1 Type: %2", key.c_str(), value.c_str());
1307
1308 cache_t::iterator p = m_cache.find(make_pair(key, value));
1309 if (p != m_cache.end())
1310 {
1311 delete_entry(&p->second, CACHE_CLOSE_DELETE);
1312 }
1313
1314 if (delete_info(key, value))
1315 {
1316 remove_cachefile(key, value);
1317 }
1318
1319 free_bytes += filesizes[n++];
1320
1321 if (free_bytes >= params.m_min_diskspace + predicted_filesize)
1322 {
1323 break;
1324 }
1325 }
1326 Logging::trace(cachepath, "Disk space after prune: %1", format_size(free_bytes).c_str());
1327 }
1328 else
1329 {
1330 Logging::error(cachepath, "Failed to execute select. Return code: %1 Error: %2 SQL: %3", ret, sqlite3_errmsg(*m_cacheidx_db), expanded_sql(stmt).c_str());
1331 }
1332
1333 sqlite3_finalize(stmt);
1334 }
1335
1336 return true;
1337}
1338
1339bool Cache::maintenance(size_t predicted_filesize)
1340{
1341 bool success = true;
1342
1343 // Find and remove expired cache entries
1344 success &= prune_expired();
1345
1346 // Check max. cache size
1347 success &= prune_cache_size();
1348
1349 // Check min. diskspace required for cache
1350 success &= prune_disk_space(predicted_filesize);
1351
1352 return success;
1353}
1354
1355bool Cache::clear()
1356{
1357 bool success = true;
1358
1359 std::lock_guard<std::recursive_mutex> lock_mutex(m_mutex);
1360
1361 std::vector<cache_key_t> keys;
1362 sqlite3_stmt * stmt;
1363 const char * sql;
1364
1365 sql = "SELECT filename, desttype FROM cache_entry;\n";
1366
1367 sqlite3_prepare(*m_cacheidx_db, sql, -1, &stmt, nullptr);
1368
1369 int ret = 0;
1370 while((ret = sqlite3_step(stmt)) == SQLITE_ROW)
1371 {
1372 const char *filename = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0));
1373 const char *desttype = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1));
1374
1375 keys.emplace_back(filename, desttype);
1376 }
1377
1378 Logging::trace(m_cacheidx_db->filename(), "Clearing all %1 entries from cache...", keys.size());
1379
1380 if (ret == SQLITE_DONE)
1381 {
1382 for (const auto& [key, value] : keys)
1383 {
1384 Logging::trace(m_cacheidx_db->filename(), "Pruning: %1 Type: %2", key.c_str(), value.c_str());
1385
1386 cache_t::iterator p = m_cache.find(make_pair(key, value));
1387 if (p != m_cache.end())
1388 {
1389 delete_entry(&p->second, CACHE_CLOSE_DELETE);
1390 }
1391
1392 if (delete_info(key, value))
1393 {
1394 remove_cachefile(key, value);
1395 }
1396 }
1397 }
1398 else
1399 {
1400 Logging::error(m_cacheidx_db->filename(), "Failed to execute select. Return code: %1 Error: %2 SQL: %3", ret, sqlite3_errmsg(*m_cacheidx_db), expanded_sql(stmt).c_str());
1401 }
1402
1403 sqlite3_finalize(stmt);
1404
1405 return success;
1406}
1407
1408bool Cache::remove_cachefile(const std::string & filename, const std::string & fileext)
1409{
1410 std::string cachefile;
1411 bool success;
1412
1413 Buffer::make_cachefile_name(&cachefile, filename, fileext, false);
1414
1415 success = Buffer::remove_file(cachefile);
1416
1417 Buffer::make_cachefile_name(&cachefile, filename, fileext, true);
1419 if (!Buffer::remove_file(cachefile) && errno != ENOENT)
1420 {
1421 success = false;
1422 }
1423
1424 return success;
1425}
1426
1427std::string Cache::expanded_sql(sqlite3_stmt *pStmt)
1428{
1429 std::string sql;
1430#ifdef HAVE_SQLITE_EXPANDED_SQL
1431 char * p = sqlite3_expanded_sql(pStmt);
1432 sql = p;
1433 sqlite3_free(p);
1434#else
1435 const char *p = sqlite3_sql(pStmt);
1436 if (p != nullptr)
1438 sql=p;
1439 }
1440 else
1441 {
1442 sql="(nullptr)";
1443 }
1444#endif
1445 return sql;
1446}
#define CACHE_CLOSE_FREE
Free memory for cache entry.
Definition: buffer.h:46
#define CACHE_CHECK_BIT(mask, var)
Check bit in bitmask.
Definition: buffer.h:43
#define CACHE_CLOSE_DELETE
Delete cache entry, will unlink cached file! Implies CACHE_CLOSE_FREE.
Definition: buffer.h:47
#define SQLBINDTXT(idx, var)
Bind text column to SQLite statement.
Definition: cache.cc:888
#define sqlite3_errstr(rc)
If our version of SQLite hasn't go this function.
Definition: cache.cc:42
#define SQLBINDNUM(func, idx, var)
Bind numeric column to SQLite statement.
Definition: cache.cc:900
#define TOSTRING(x)
Convert a macro argument into a string constant.
Definition: cache.cc:46
Data cache management.
#define DB_VERSION_MINOR
Current database version minor.
Definition: cache.h:46
#define DB_MIN_VERSION_MAJOR
Required database version major (required 1.95)
Definition: cache.h:48
#define DB_MIN_VERSION_MINOR
Required database version minor (required 1.95)
Definition: cache.h:49
#define DB_VERSION_MAJOR
Current database version major.
Definition: cache.h:45
RESULTCODE
RESULTCODE of transcoding operation.
Definition: cache.h:58
@ NONE
No result code available.
#define DB_BASE_VERSION_MINOR
The oldest database version minor (Release < 1.95)
Definition: cache.h:43
#define DB_BASE_VERSION_MAJOR
The oldest database version major (Release < 1.95)
Definition: cache.h:42
CACHE_INFO const * LPCCACHE_INFO
Pointer version of CACHE_INFO.
Definition: cache.h:96
struct sqlite3_stmt sqlite3_stmt
Forward declaration of sqlite3 statement handle.
Definition: cache.h:52
Cache entry
static bool remove_file(const std::string &filename)
Remove (unlink) the file.
Definition: buffer.cc:995
static const std::string & make_cachefile_name(std::string *cachefile, const std::string &filename, const std::string &fileext, bool is_idx)
Make up a cache file name, including the full path.
Definition: buffer.cc:975
sqlite3 * m_db_handle
SQLite handle of cache index database.
Definition: cache.h:186
std::string m_filename
Name of SQLite cache index database.
Definition: cache.h:185
virtual ~sqlite_t()
Free sqlite_t object.
Definition: cache.cc:58
sqlite_t(const std::string &filename, int flags, const char *zVfs=nullptr)
Construct sqlite_t object.
Definition: cache.cc:48
int m_ret
Return code of last SQL operation.
Definition: cache.h:184
The Cache_Entry class.
Definition: cache_entry.h:49
static Cache_Entry * create(Cache *owner, LPVIRTUALFILE virtualfile)
Create a new Cache_Entry object.
Definition: cache_entry.cc:74
Cache_Entry * openio(LPVIRTUALFILE virtualfile)
Open cache entry.
Definition: cache.cc:1075
static const TABLECOLUMNS_VEC m_columns_cache_entry
Columns of table "cache_entry".
Definition: cache.h:374
bool prune_disk_space(size_t predicted_filesize)
Prune cache entries to ensure disk space.
Definition: cache.cc:1257
bool delete_info(const std::string &filename, const std::string &desttype)
Delete cache file info.
Definition: cache.cc:978
bool delete_entry(Cache_Entry **cache_entry, int flags)
Delete cache entry object.
Definition: cache.cc:1051
int cmp_version(int version_major_l, int version_minor_l, int version_major_r, int version_minor_r)
Compare two versions.
Definition: cache.cc:276
bool create_table_cache_entry(LPCTABLE_DEF table, const TABLECOLUMNS_VEC &columns)
Create cache_entry table.
Definition: cache.cc:351
bool clear()
Clear cache: deletes all entries.
Definition: cache.cc:1365
cache_t m_cache
Cache file (memory mapped file)
Definition: cache.h:382
bool prepare_stmts()
Prepare all SQL statements.
Definition: cache.cc:155
bool remove_cachefile(const std::string &filename, const std::string &fileext)
Remove a cache file from disk.
Definition: cache.cc:1418
bool maintenance(size_t predicted_filesize=0)
Run disk maintenance.
Definition: cache.cc:1349
Cache()
Construct Cache object.
Definition: cache.cc:138
std::vector< TABLE_COLUMNS > TABLECOLUMNS_VEC
Table columns array.
Definition: cache.h:131
std::string expanded_sql(sqlite3_stmt *pStmt)
Get expanded SQL string for a statement.
Definition: cache.cc:1437
TABLE_DEF const * LPCTABLE_DEF
Pointer version of TABLE_DEF.
Definition: cache.h:117
bool load_index()
Load cache index from disk.
Definition: cache.cc:611
bool write_info(LPCCACHE_INFO cache_info)
Write cache file info.
Definition: cache.cc:912
std::unique_ptr< sqlite_t > m_cacheidx_db
SQLite handle of cache index database.
Definition: cache.h:380
static const TABLECOLUMNS_VEC m_columns_version
Columns of table "version".
Definition: cache.h:376
static const TABLE_DEF m_table_version
Definition and indexes of table "version".
Definition: cache.h:375
bool rollback_transaction()
Rollback a database transaction.
Definition: cache.cc:335
void close_index()
Close cache index.
Definition: cache.cc:1031
bool begin_transaction()
Begin a database transactio.n.
Definition: cache.cc:303
bool read_info(LPCACHE_INFO cache_info)
Read cache file info.
Definition: cache.cc:785
bool table_exists(const char *table)
Check if SQL table exists in database.
Definition: cache.cc:189
bool end_transaction()
End a database transaction.
Definition: cache.cc:319
bool upgrade_db(int *db_version_major, int *db_version_minor)
Upgrade database from version below 1.95.
Definition: cache.cc:391
bool prune_cache_size()
Prune cache entries to keep cache size within limit.
Definition: cache.cc:1179
std::recursive_mutex m_mutex
Access mutex.
Definition: cache.h:378
bool closeio(Cache_Entry **cache_entry, int flags=CACHE_CLOSE_NOOPT)
Close a cache entry.
Definition: cache.cc:1093
Cache_Entry * create_entry(LPVIRTUALFILE virtualfile, const std::string &desttype)
Create cache entry object for a VIRTUALFILE.
Definition: cache.cc:1036
bool column_exists(const char *table, const char *column)
Check if column exists in SQL table.
Definition: cache.cc:218
bool prune_expired()
Prune expired cache entries.
Definition: cache.cc:1117
bool check_min_version(int *db_version_major, int *db_version_minor)
Check the db version if upgrade needed.
Definition: cache.cc:249
virtual ~Cache()
Destruct Cache object.
Definition: cache.cc:142
static const TABLE_DEF m_table_cache_entry
Definition and indexes of table "cache_entry".
Definition: cache.h:373
const std::string & desttype() const
Get destination type.
static void warning(const T filename, const std::string &format_string, Args &&...args)
Write warning level log entry.
Definition: logging.h:220
static void debug(const T filename, const std::string &format_string, Args &&...args)
Write debug level log entry.
Definition: logging.h:182
static void trace(const T filename, const std::string &format_string, Args &&...args)
Write trace level log entry.
Definition: logging.h:163
static void info(const T filename, const std::string &format_string, Args &&...args)
Write info level log entry.
Definition: logging.h:201
static void error(const T filename, const std::string &format_string, Args &&...args)
Write error level log entry.
Definition: logging.h:239
int mktree(const std::string &path, mode_t mode)
Make directory tree.
const std::string & append_filename(std::string *path, const std::string &filename)
Add filename to path, including / after the path if required.
size_t get_disk_free(std::string &path)
Get free disk space.
std::string format_time(time_t value)
Format a time in format "w d m s".
std::string format_size(uint64_t value)
Format size.
const std::string & strsprintf(std::string *str, const std::string &format, Args ... args)
Format a std::string sprintf-like.
Definition: ffmpeg_utils.h:737
FFMPEGFS_PARAMS params
FFmpegfs command line parameters.
Definition: ffmpegfs.cc:74
Main include for FFmpegfs project.
void transcoder_cache_path(std::string *path)
Get transcoder cache path.
Definition: transcode.cc:195
Provide various log facilities to stderr, disk or syslog.
Cache information block.
Definition: cache.h:71
uint32_t m_video_frame_count
Number of frames in video or 0 if not a video.
Definition: cache.h:84
int64_t m_audiobitrate
Audio bitrate in bit/s.
Definition: cache.h:75
size_t m_file_size
Source file file size.
Definition: cache.h:93
time_t m_access_time
Source file last access time.
Definition: cache.h:91
RESULTCODE m_result
Result code:
Definition: cache.h:86
bool m_deinterlace
true if video was deinterlaced
Definition: cache.h:80
int64_t m_duration
File duration, in AV_TIME_BASE fractional seconds.
Definition: cache.h:81
uint32_t m_segment_count
Number of segments for HLS.
Definition: cache.h:85
size_t m_encoded_filesize
Actual file size after encode.
Definition: cache.h:83
int m_audiosamplerate
Audio sample rate in Hz.
Definition: cache.h:76
bool m_error
true if encode failed
Definition: cache.h:87
size_t m_predicted_filesize
Predicted file size.
Definition: cache.h:82
std::string m_destfile
Destination filename after transcode.
Definition: cache.h:73
int m_averror
FFmpeg error code if encode failed.
Definition: cache.h:89
time_t m_file_time
Source file file time.
Definition: cache.h:92
std::array< char, 11 > m_desttype
Destination type.
Definition: cache.h:74
int m_videowidth
Video width.
Definition: cache.h:78
int m_videoheight
Video height.
Definition: cache.h:79
int64_t m_videobitrate
Video bitrate in bit/s.
Definition: cache.h:77
int m_errno
errno if encode failed
Definition: cache.h:88
time_t m_creation_time
Source file creation time.
Definition: cache.h:90
Column definition of sql table.
Definition: cache.h:124
Definition of sql table.
Definition: cache.h:113
const char * name
Table name.
Definition: cache.h:114
time_t m_expiry_time
Time (seconds) after which an cache entry is deleted.
Definition: ffmpegfs.h:242
const FFmpegfs_Format * current_format(LPCVIRTUALFILE virtualfile) const
Get FFmpegfs_Format for a virtual file.
Definition: ffmpegfs.cc:235
size_t m_max_cache_size
Max. cache size in MB. When exceeded, oldest entries will be pruned.
Definition: ffmpegfs.h:247
size_t m_min_diskspace
Min. diskspace required for cache.
Definition: ffmpegfs.h:248
Virtual file definition.
Definition: fileio.h:123
std::string m_destfile
Name and path of destination file.
Definition: fileio.h:150