diff options
| -rw-r--r-- | org/in_source_files.org | 185 | ||||
| -rw-r--r-- | src/sisudoc/ocda/abstraction/db_in.d | 177 | ||||
| -rw-r--r-- | src/sisudoc/ocda/abstraction/ssp_in.d | 8 |
3 files changed, 222 insertions, 148 deletions
diff --git a/org/in_source_files.org b/org/in_source_files.org index 6b645b6..e78970a 100644 --- a/org/in_source_files.org +++ b/org/in_source_files.org @@ -1131,7 +1131,11 @@ template spineAbstractionRead() { } return true; } - SSPdocument sspReadFile(string file_path) { + /+ ↓ with_digest is off by default: hashing the file is only wanted where + the digest is going to be recorded, and on the largest document in the + sample set it is a tenth of what reading the file costs + +/ + SSPdocument sspReadFile(string file_path, bool with_digest = false) { string _text; string[] _lines; try { @@ -1143,7 +1147,7 @@ template spineAbstractionRead() { } auto _doc = sspRead(_lines); if (!sspFormatVersionOk(_doc.format, file_path)) { return SSPdocument(); } - _doc.ssp_digest = sspDigestOfText(_text); + if (with_digest) { _doc.ssp_digest = sspDigestOfText(_text); } return _doc; } } @@ -1278,6 +1282,44 @@ template spineAbstractionDbRead() { } } if (!sspFormatVersionOk(doc.format, db_file)) { return SSPdocument(); } + /+ ↓ the per object lists, gathered first, one sweep of each table. + + these four tables hold what a single object row cannot: the images + an object carries, the links stowed off it, its anchor tags and its + lev4 subtoc entries. They are read here in four ordered passes and + kept by object id, rather than queried per object as the objects are + built. The cost is then what the tables hold, not what the document + holds: war and peace has 12,135 objects and 138 rows across all + four, which as four statements per object was 48,540 statement + preparations and made reading a .ocda.db slower than parsing the + markup it came from. + +/ + ST_file_name_hash_size_[][long] _images_by_id; + string[][long] _links_by_id; + string[][long] _anchors_by_id; + string[][long] _subtoc_by_id; + foreach (r; db.execute( + "SELECT object_id, name, bytes, sha256, width, height, missing" + ~ " FROM object_images ORDER BY object_id, seq") + ) { + ST_file_name_hash_size_ _img; + _img.fileName = r["name"].as!string; + _img.fileSize = r["bytes"].as!ulong; + _img.fileHash_sha256 = _hex32(r["sha256"].as!string); + _img.imageWidth = r["width"].as!int; + _img.imageHeight = r["height"].as!int; + _img.fileMissing = (r["missing"].as!int == 1); + _images_by_id[r["object_id"].as!long] ~= _img; + } + foreach (r; db.execute( + "SELECT object_id, url FROM object_links ORDER BY object_id, seq") + ) { _links_by_id[r["object_id"].as!long] ~= r["url"].as!string; } + foreach (r; db.execute( + "SELECT object_id, anchor FROM object_anchors ORDER BY object_id, seq") + ) { _anchors_by_id[r["object_id"].as!long] ~= r["anchor"].as!string; } + foreach (r; db.execute( + "SELECT object_id, entry FROM object_subtoc ORDER BY object_id, seq") + ) { _subtoc_by_id[r["object_id"].as!long] ~= r["entry"].as!string; } /+ ↓ the objects, section by section, in the order they were written +/ string[] _sections; foreach (row; db.execute( @@ -1288,93 +1330,88 @@ template spineAbstractionDbRead() { foreach (section; _sections) { doc.section_order ~= section; doc.abstraction[section] = []; + /+ ↓ column name to index, resolved once for the statement. + + d2sqlite3's row["name"] is indexForName, a linear scan over the + columns that calls sqlite3_column_name and allocates a D string + for each one it passes. With some fifty named reads per object + over forty columns that is around a thousand of those per object, + and it was the larger half of what made reading a database slow. + Resolved once here, the reads below are an integer index. + +/ + int[string] _col; foreach (row; db.execute( "SELECT * FROM objects WHERE section = '" ~ section ~ "' ORDER BY seq") ) { + if (_col.length == 0) { + foreach (_i; 0 .. row.length) { _col[row.columnName(_i)] = _i.to!int; } + } ObjGenericComposite obj; - long _id = row["id"].as!long; - obj.metainfo.ocn = row["ocn"].as!int; - obj.metainfo.is_a = row["is_a"].as!string; - obj.metainfo.is_of_part = row["is_of_part"].as!string; - obj.metainfo.is_of_section = (row["is_of_section"].as!string.length > 0) - ? row["is_of_section"].as!string : section; - obj.metainfo.is_of_type = row["is_of_type"].as!string; - obj.metainfo.identifier = row["identifier"].as!string; + long _id = row[_col["id"]].as!long; + obj.metainfo.ocn = row[_col["ocn"]].as!int; + obj.metainfo.is_a = row[_col["is_a"]].as!string; + obj.metainfo.is_of_part = row[_col["is_of_part"]].as!string; + obj.metainfo.is_of_section = (row[_col["is_of_section"]].as!string.length > 0) + ? row[_col["is_of_section"]].as!string : section; + obj.metainfo.is_of_type = row[_col["is_of_type"]].as!string; + obj.metainfo.identifier = row[_col["identifier"]].as!string; obj.metainfo.heading_lev_markup = (obj.metainfo.is_a == "heading") - ? row["heading_level"].as!int : 9; - obj.metainfo.heading_lev_collapsed = (row["heading_lev_collapsed"].as!string.length > 0) - ? row["heading_lev_collapsed"].as!int : 9; - obj.metainfo.parent_ocn = row["parent_ocn"].as!int; - obj.metainfo.parent_lev_markup = row["parent_lev"].as!int; - obj.metainfo.last_descendant_ocn = row["last_descendant_ocn"].as!int; - obj.metainfo.children_headings = _jsonInts(row["children"].as!string); - obj.metainfo.markedup_ancestors = _jsonEight(row["ancestors"].as!string); - obj.metainfo.collapsed_ancestors = _jsonEight(row["ancestors_collapsed"].as!string); + ? row[_col["heading_level"]].as!int : 9; + obj.metainfo.heading_lev_collapsed = (row[_col["heading_lev_collapsed"]].as!string.length > 0) + ? row[_col["heading_lev_collapsed"]].as!int : 9; + obj.metainfo.parent_ocn = row[_col["parent_ocn"]].as!int; + obj.metainfo.parent_lev_markup = row[_col["parent_lev"]].as!int; + obj.metainfo.last_descendant_ocn = row[_col["last_descendant_ocn"]].as!int; + obj.metainfo.children_headings = _jsonInts(row[_col["children"]].as!string); + obj.metainfo.markedup_ancestors = _jsonEight(row[_col["ancestors"]].as!string); + obj.metainfo.collapsed_ancestors = _jsonEight(row[_col["ancestors_collapsed"]].as!string); obj.metainfo.dom_structure_markedup_tags_status - = _jsonEight(row["dom_status"].as!string); + = _jsonEight(row[_col["dom_status"]].as!string); obj.metainfo.dom_structure_collapsed_tags_status - = _jsonEight(row["dom_status_collapsed"].as!string); - obj.metainfo.dummy_heading = (row["dummy_heading"].as!int == 1); - obj.metainfo.object_number_off = (row["object_number_off"].as!int == 1); - obj.metainfo.attrib = row["attrib"].as!string; - obj.metainfo.lang = row["meta_lang"].as!string; - obj.metainfo.syntax = row["meta_syntax"].as!string; - obj.metainfo.sha256.text = _hex32(row["sha256"].as!string); - obj.attrib.indent_base = row["indent_base"].as!int; - obj.attrib.indent_hang = row["indent_hang"].as!int; - obj.attrib.bullet = (row["bullet"].as!int == 1); - obj.attrib.language = row["lang"].as!string; - obj.has.inline_links = (row["has_links"].as!int == 1); - obj.has.inline_notes_reg = (row["has_notes_reg"].as!int == 1); - obj.has.inline_notes_star = (row["has_notes_star"].as!int == 1); - obj.has.images = (row["has_images"].as!int == 1); - obj.has.image_without_dimensions = (row["has_images_no_dim"].as!int == 1); - obj.tags.in_segment_html = row["segment"].as!string; - obj.tags.segname_prev = row["segment_prev"].as!string; - obj.tags.segname_next = row["segment_next"].as!string; - obj.tags.segment_anchor_tag_epub = row["segment_epub"].as!string; - obj.tags.html_segment_anchor_tag_is = row["segment_html_is"].as!string; - obj.tags.epub_segment_anchor_tag_is = row["segment_epub_is"].as!string; - obj.tags.anchor_tag_html = row["anchor"].as!string; - obj.tags.heading_lev_anchor_tag = row["heading_lev_anchor"].as!string; + = _jsonEight(row[_col["dom_status_collapsed"]].as!string); + obj.metainfo.dummy_heading = (row[_col["dummy_heading"]].as!int == 1); + obj.metainfo.object_number_off = (row[_col["object_number_off"]].as!int == 1); + obj.metainfo.attrib = row[_col["attrib"]].as!string; + obj.metainfo.lang = row[_col["meta_lang"]].as!string; + obj.metainfo.syntax = row[_col["meta_syntax"]].as!string; + obj.metainfo.sha256.text = _hex32(row[_col["sha256"]].as!string); + obj.attrib.indent_base = row[_col["indent_base"]].as!int; + obj.attrib.indent_hang = row[_col["indent_hang"]].as!int; + obj.attrib.bullet = (row[_col["bullet"]].as!int == 1); + obj.attrib.language = row[_col["lang"]].as!string; + obj.has.inline_links = (row[_col["has_links"]].as!int == 1); + obj.has.inline_notes_reg = (row[_col["has_notes_reg"]].as!int == 1); + obj.has.inline_notes_star = (row[_col["has_notes_star"]].as!int == 1); + obj.has.images = (row[_col["has_images"]].as!int == 1); + obj.has.image_without_dimensions = (row[_col["has_images_no_dim"]].as!int == 1); + obj.tags.in_segment_html = row[_col["segment"]].as!string; + obj.tags.segname_prev = row[_col["segment_prev"]].as!string; + obj.tags.segname_next = row[_col["segment_next"]].as!string; + obj.tags.segment_anchor_tag_epub = row[_col["segment_epub"]].as!string; + obj.tags.html_segment_anchor_tag_is = row[_col["segment_html_is"]].as!string; + obj.tags.epub_segment_anchor_tag_is = row[_col["segment_epub_is"]].as!string; + obj.tags.anchor_tag_html = row[_col["anchor"]].as!string; + obj.tags.heading_lev_anchor_tag = row[_col["heading_lev_anchor"]].as!string; { string[8] _h; - foreach (i, h; _jsonStrs(row["heading_ancestors_text"].as!string)) { + foreach (i, h; _jsonStrs(row[_col["heading_ancestors_text"]].as!string)) { if (i < _h.length) { _h[i] = h; } } obj.tags.heading_ancestors_text = _h; } if (obj.metainfo.is_a == "table") { - obj.table.number_of_columns = row["table_cols"].as!int; - obj.table.column_widths = _jsonDoubles(row["table_widths"].as!string); - obj.table.column_aligns = _jsonStrs(row["table_aligns"].as!string); - obj.table.heading = (row["table_header"].as!int == 1); - } - obj.code_block.linenumbers = (row["code_linenumbers"].as!int == 1); - obj.text = row["text"].as!string; - /+ ↓ the per object lists +/ - foreach (r; db.execute( - "SELECT name, bytes, sha256, width, height, missing FROM object_images" - ~ " WHERE object_id = " ~ _id.to!string ~ " ORDER BY seq") - ) { - ST_file_name_hash_size_ _img; - _img.fileName = r["name"].as!string; - _img.fileSize = r["bytes"].as!ulong; - _img.fileHash_sha256 = _hex32(r["sha256"].as!string); - _img.imageWidth = r["width"].as!int; - _img.imageHeight = r["height"].as!int; - _img.fileMissing = (r["missing"].as!int == 1); - obj.metainfo.sha256.images ~= _img; + obj.table.number_of_columns = row[_col["table_cols"]].as!int; + obj.table.column_widths = _jsonDoubles(row[_col["table_widths"]].as!string); + obj.table.column_aligns = _jsonStrs(row[_col["table_aligns"]].as!string); + obj.table.heading = (row[_col["table_header"]].as!int == 1); } - foreach (r; db.execute( - "SELECT url FROM object_links WHERE object_id = " ~ _id.to!string ~ " ORDER BY seq") - ) { obj.stow.link ~= r["url"].as!string; } - foreach (r; db.execute( - "SELECT anchor FROM object_anchors WHERE object_id = " ~ _id.to!string ~ " ORDER BY seq") - ) { obj.tags.anchor_tags ~= r["anchor"].as!string; } - foreach (r; db.execute( - "SELECT entry FROM object_subtoc WHERE object_id = " ~ _id.to!string ~ " ORDER BY seq") - ) { obj.tags.lev4_subtoc ~= r["entry"].as!string; } + obj.code_block.linenumbers = (row[_col["code_linenumbers"]].as!int == 1); + obj.text = row[_col["text"]].as!string; + /+ ↓ the per object lists, from the sweeps above +/ + if (auto _v = _id in _images_by_id) { obj.metainfo.sha256.images = *_v; } + if (auto _v = _id in _links_by_id) { obj.stow.link = *_v; } + if (auto _v = _id in _anchors_by_id) { obj.tags.anchor_tags = *_v; } + if (auto _v = _id in _subtoc_by_id) { obj.tags.lev4_subtoc = *_v; } doc.abstraction[section] ~= obj; } } diff --git a/src/sisudoc/ocda/abstraction/db_in.d b/src/sisudoc/ocda/abstraction/db_in.d index 3d10540..0d78f12 100644 --- a/src/sisudoc/ocda/abstraction/db_in.d +++ b/src/sisudoc/ocda/abstraction/db_in.d @@ -169,6 +169,44 @@ template spineAbstractionDbRead() { } } if (!sspFormatVersionOk(doc.format, db_file)) { return SSPdocument(); } + /+ ↓ the per object lists, gathered first, one sweep of each table. + + these four tables hold what a single object row cannot: the images + an object carries, the links stowed off it, its anchor tags and its + lev4 subtoc entries. They are read here in four ordered passes and + kept by object id, rather than queried per object as the objects are + built. The cost is then what the tables hold, not what the document + holds: war and peace has 12,135 objects and 138 rows across all + four, which as four statements per object was 48,540 statement + preparations and made reading a .ocda.db slower than parsing the + markup it came from. + +/ + ST_file_name_hash_size_[][long] _images_by_id; + string[][long] _links_by_id; + string[][long] _anchors_by_id; + string[][long] _subtoc_by_id; + foreach (r; db.execute( + "SELECT object_id, name, bytes, sha256, width, height, missing" + ~ " FROM object_images ORDER BY object_id, seq") + ) { + ST_file_name_hash_size_ _img; + _img.fileName = r["name"].as!string; + _img.fileSize = r["bytes"].as!ulong; + _img.fileHash_sha256 = _hex32(r["sha256"].as!string); + _img.imageWidth = r["width"].as!int; + _img.imageHeight = r["height"].as!int; + _img.fileMissing = (r["missing"].as!int == 1); + _images_by_id[r["object_id"].as!long] ~= _img; + } + foreach (r; db.execute( + "SELECT object_id, url FROM object_links ORDER BY object_id, seq") + ) { _links_by_id[r["object_id"].as!long] ~= r["url"].as!string; } + foreach (r; db.execute( + "SELECT object_id, anchor FROM object_anchors ORDER BY object_id, seq") + ) { _anchors_by_id[r["object_id"].as!long] ~= r["anchor"].as!string; } + foreach (r; db.execute( + "SELECT object_id, entry FROM object_subtoc ORDER BY object_id, seq") + ) { _subtoc_by_id[r["object_id"].as!long] ~= r["entry"].as!string; } /+ ↓ the objects, section by section, in the order they were written +/ string[] _sections; foreach (row; db.execute( @@ -179,93 +217,88 @@ template spineAbstractionDbRead() { foreach (section; _sections) { doc.section_order ~= section; doc.abstraction[section] = []; + /+ ↓ column name to index, resolved once for the statement. + + d2sqlite3's row["name"] is indexForName, a linear scan over the + columns that calls sqlite3_column_name and allocates a D string + for each one it passes. With some fifty named reads per object + over forty columns that is around a thousand of those per object, + and it was the larger half of what made reading a database slow. + Resolved once here, the reads below are an integer index. + +/ + int[string] _col; foreach (row; db.execute( "SELECT * FROM objects WHERE section = '" ~ section ~ "' ORDER BY seq") ) { + if (_col.length == 0) { + foreach (_i; 0 .. row.length) { _col[row.columnName(_i)] = _i.to!int; } + } ObjGenericComposite obj; - long _id = row["id"].as!long; - obj.metainfo.ocn = row["ocn"].as!int; - obj.metainfo.is_a = row["is_a"].as!string; - obj.metainfo.is_of_part = row["is_of_part"].as!string; - obj.metainfo.is_of_section = (row["is_of_section"].as!string.length > 0) - ? row["is_of_section"].as!string : section; - obj.metainfo.is_of_type = row["is_of_type"].as!string; - obj.metainfo.identifier = row["identifier"].as!string; + long _id = row[_col["id"]].as!long; + obj.metainfo.ocn = row[_col["ocn"]].as!int; + obj.metainfo.is_a = row[_col["is_a"]].as!string; + obj.metainfo.is_of_part = row[_col["is_of_part"]].as!string; + obj.metainfo.is_of_section = (row[_col["is_of_section"]].as!string.length > 0) + ? row[_col["is_of_section"]].as!string : section; + obj.metainfo.is_of_type = row[_col["is_of_type"]].as!string; + obj.metainfo.identifier = row[_col["identifier"]].as!string; obj.metainfo.heading_lev_markup = (obj.metainfo.is_a == "heading") - ? row["heading_level"].as!int : 9; - obj.metainfo.heading_lev_collapsed = (row["heading_lev_collapsed"].as!string.length > 0) - ? row["heading_lev_collapsed"].as!int : 9; - obj.metainfo.parent_ocn = row["parent_ocn"].as!int; - obj.metainfo.parent_lev_markup = row["parent_lev"].as!int; - obj.metainfo.last_descendant_ocn = row["last_descendant_ocn"].as!int; - obj.metainfo.children_headings = _jsonInts(row["children"].as!string); - obj.metainfo.markedup_ancestors = _jsonEight(row["ancestors"].as!string); - obj.metainfo.collapsed_ancestors = _jsonEight(row["ancestors_collapsed"].as!string); + ? row[_col["heading_level"]].as!int : 9; + obj.metainfo.heading_lev_collapsed = (row[_col["heading_lev_collapsed"]].as!string.length > 0) + ? row[_col["heading_lev_collapsed"]].as!int : 9; + obj.metainfo.parent_ocn = row[_col["parent_ocn"]].as!int; + obj.metainfo.parent_lev_markup = row[_col["parent_lev"]].as!int; + obj.metainfo.last_descendant_ocn = row[_col["last_descendant_ocn"]].as!int; + obj.metainfo.children_headings = _jsonInts(row[_col["children"]].as!string); + obj.metainfo.markedup_ancestors = _jsonEight(row[_col["ancestors"]].as!string); + obj.metainfo.collapsed_ancestors = _jsonEight(row[_col["ancestors_collapsed"]].as!string); obj.metainfo.dom_structure_markedup_tags_status - = _jsonEight(row["dom_status"].as!string); + = _jsonEight(row[_col["dom_status"]].as!string); obj.metainfo.dom_structure_collapsed_tags_status - = _jsonEight(row["dom_status_collapsed"].as!string); - obj.metainfo.dummy_heading = (row["dummy_heading"].as!int == 1); - obj.metainfo.object_number_off = (row["object_number_off"].as!int == 1); - obj.metainfo.attrib = row["attrib"].as!string; - obj.metainfo.lang = row["meta_lang"].as!string; - obj.metainfo.syntax = row["meta_syntax"].as!string; - obj.metainfo.sha256.text = _hex32(row["sha256"].as!string); - obj.attrib.indent_base = row["indent_base"].as!int; - obj.attrib.indent_hang = row["indent_hang"].as!int; - obj.attrib.bullet = (row["bullet"].as!int == 1); - obj.attrib.language = row["lang"].as!string; - obj.has.inline_links = (row["has_links"].as!int == 1); - obj.has.inline_notes_reg = (row["has_notes_reg"].as!int == 1); - obj.has.inline_notes_star = (row["has_notes_star"].as!int == 1); - obj.has.images = (row["has_images"].as!int == 1); - obj.has.image_without_dimensions = (row["has_images_no_dim"].as!int == 1); - obj.tags.in_segment_html = row["segment"].as!string; - obj.tags.segname_prev = row["segment_prev"].as!string; - obj.tags.segname_next = row["segment_next"].as!string; - obj.tags.segment_anchor_tag_epub = row["segment_epub"].as!string; - obj.tags.html_segment_anchor_tag_is = row["segment_html_is"].as!string; - obj.tags.epub_segment_anchor_tag_is = row["segment_epub_is"].as!string; - obj.tags.anchor_tag_html = row["anchor"].as!string; - obj.tags.heading_lev_anchor_tag = row["heading_lev_anchor"].as!string; + = _jsonEight(row[_col["dom_status_collapsed"]].as!string); + obj.metainfo.dummy_heading = (row[_col["dummy_heading"]].as!int == 1); + obj.metainfo.object_number_off = (row[_col["object_number_off"]].as!int == 1); + obj.metainfo.attrib = row[_col["attrib"]].as!string; + obj.metainfo.lang = row[_col["meta_lang"]].as!string; + obj.metainfo.syntax = row[_col["meta_syntax"]].as!string; + obj.metainfo.sha256.text = _hex32(row[_col["sha256"]].as!string); + obj.attrib.indent_base = row[_col["indent_base"]].as!int; + obj.attrib.indent_hang = row[_col["indent_hang"]].as!int; + obj.attrib.bullet = (row[_col["bullet"]].as!int == 1); + obj.attrib.language = row[_col["lang"]].as!string; + obj.has.inline_links = (row[_col["has_links"]].as!int == 1); + obj.has.inline_notes_reg = (row[_col["has_notes_reg"]].as!int == 1); + obj.has.inline_notes_star = (row[_col["has_notes_star"]].as!int == 1); + obj.has.images = (row[_col["has_images"]].as!int == 1); + obj.has.image_without_dimensions = (row[_col["has_images_no_dim"]].as!int == 1); + obj.tags.in_segment_html = row[_col["segment"]].as!string; + obj.tags.segname_prev = row[_col["segment_prev"]].as!string; + obj.tags.segname_next = row[_col["segment_next"]].as!string; + obj.tags.segment_anchor_tag_epub = row[_col["segment_epub"]].as!string; + obj.tags.html_segment_anchor_tag_is = row[_col["segment_html_is"]].as!string; + obj.tags.epub_segment_anchor_tag_is = row[_col["segment_epub_is"]].as!string; + obj.tags.anchor_tag_html = row[_col["anchor"]].as!string; + obj.tags.heading_lev_anchor_tag = row[_col["heading_lev_anchor"]].as!string; { string[8] _h; - foreach (i, h; _jsonStrs(row["heading_ancestors_text"].as!string)) { + foreach (i, h; _jsonStrs(row[_col["heading_ancestors_text"]].as!string)) { if (i < _h.length) { _h[i] = h; } } obj.tags.heading_ancestors_text = _h; } if (obj.metainfo.is_a == "table") { - obj.table.number_of_columns = row["table_cols"].as!int; - obj.table.column_widths = _jsonDoubles(row["table_widths"].as!string); - obj.table.column_aligns = _jsonStrs(row["table_aligns"].as!string); - obj.table.heading = (row["table_header"].as!int == 1); - } - obj.code_block.linenumbers = (row["code_linenumbers"].as!int == 1); - obj.text = row["text"].as!string; - /+ ↓ the per object lists +/ - foreach (r; db.execute( - "SELECT name, bytes, sha256, width, height, missing FROM object_images" - ~ " WHERE object_id = " ~ _id.to!string ~ " ORDER BY seq") - ) { - ST_file_name_hash_size_ _img; - _img.fileName = r["name"].as!string; - _img.fileSize = r["bytes"].as!ulong; - _img.fileHash_sha256 = _hex32(r["sha256"].as!string); - _img.imageWidth = r["width"].as!int; - _img.imageHeight = r["height"].as!int; - _img.fileMissing = (r["missing"].as!int == 1); - obj.metainfo.sha256.images ~= _img; + obj.table.number_of_columns = row[_col["table_cols"]].as!int; + obj.table.column_widths = _jsonDoubles(row[_col["table_widths"]].as!string); + obj.table.column_aligns = _jsonStrs(row[_col["table_aligns"]].as!string); + obj.table.heading = (row[_col["table_header"]].as!int == 1); } - foreach (r; db.execute( - "SELECT url FROM object_links WHERE object_id = " ~ _id.to!string ~ " ORDER BY seq") - ) { obj.stow.link ~= r["url"].as!string; } - foreach (r; db.execute( - "SELECT anchor FROM object_anchors WHERE object_id = " ~ _id.to!string ~ " ORDER BY seq") - ) { obj.tags.anchor_tags ~= r["anchor"].as!string; } - foreach (r; db.execute( - "SELECT entry FROM object_subtoc WHERE object_id = " ~ _id.to!string ~ " ORDER BY seq") - ) { obj.tags.lev4_subtoc ~= r["entry"].as!string; } + obj.code_block.linenumbers = (row[_col["code_linenumbers"]].as!int == 1); + obj.text = row[_col["text"]].as!string; + /+ ↓ the per object lists, from the sweeps above +/ + if (auto _v = _id in _images_by_id) { obj.metainfo.sha256.images = *_v; } + if (auto _v = _id in _links_by_id) { obj.stow.link = *_v; } + if (auto _v = _id in _anchors_by_id) { obj.tags.anchor_tags = *_v; } + if (auto _v = _id in _subtoc_by_id) { obj.tags.lev4_subtoc = *_v; } doc.abstraction[section] ~= obj; } } diff --git a/src/sisudoc/ocda/abstraction/ssp_in.d b/src/sisudoc/ocda/abstraction/ssp_in.d index 71daf50..873cb7e 100644 --- a/src/sisudoc/ocda/abstraction/ssp_in.d +++ b/src/sisudoc/ocda/abstraction/ssp_in.d @@ -394,7 +394,11 @@ template spineAbstractionRead() { } return true; } - SSPdocument sspReadFile(string file_path) { + /+ ↓ with_digest is off by default: hashing the file is only wanted where + the digest is going to be recorded, and on the largest document in the + sample set it is a tenth of what reading the file costs + +/ + SSPdocument sspReadFile(string file_path, bool with_digest = false) { string _text; string[] _lines; try { @@ -406,7 +410,7 @@ template spineAbstractionRead() { } auto _doc = sspRead(_lines); if (!sspFormatVersionOk(_doc.format, file_path)) { return SSPdocument(); } - _doc.ssp_digest = sspDigestOfText(_text); + if (with_digest) { _doc.ssp_digest = sspDigestOfText(_text); } return _doc; } } |
