nexusphp icon indicating copy to clipboard operation
nexusphp copied to clipboard

对 `files` 表进行优化建议

Open Rhilip opened this issue 3 years ago • 2 comments

在上传种子的时候,如果种子包含的文件数过多,会对 files 表产生大量 insert 操作,并在用户检索对应种子文件列表的时候,select 操作传输过多数据。此外, files 表中 filename 列在文件较深的情况下,会产生大量重复字段。

以上,建议对 files 表进行优化,直接在 files 表中存入树状结构的 json 文本,并在检索种子文件列表操作时直接返回数据库文本即可。实测能解决部分种子上传超时问题。


存入的 json 结构如下:

对于单文件种子:

{
    "torrentName": {   // 种子名
        "file1": 12345678   // 文件+大小
    }
}

对于多文件种子:

{
    "torrentName": {   // 种子名
        "Dir1": {   // 子文件夹
            "file1": 12345678,   //  文件+大小
        },
        "file2": 12345678,
        "file3": 12345678 
    }
}

此处提供部分 patch (因为完整的未形成展示性 pr )

  • 对 files 表结构进行修改(或另建一个表)
  • 文件 takeupload.php 进行修改

/** 前面需要把 $filelist 从 Array<Array<string,string>> 变成 Dict<string,string>

// 修改前 
$filelist[] = array($dname, $totallen);
$filelist[] = [$ffe, $ll];

// 修改后
$filelist[$dname] = $totallen;
$filelist[$ffe] = $ll;
*/

// after get torrent id

// 生成新的files表
function getFileTree($array, $delimiter = '/')
{
    if (!is_array($array)) {
        return [];
    }

    $splitRE = '/' . preg_quote($delimiter, '/') . '/';
    $returnArr = [];
    foreach ($array as $key => $val) {
        // Get parent parts and the current leaf
        $parts = preg_split($splitRE, $key, -1, PREG_SPLIT_NO_EMPTY);
        $leafPart = array_pop($parts);

        // Build parent structure
        // Might be slow for really deep and large structures
        $parentArr = &$returnArr;
        foreach ($parts as $part) {
            if (!isset($parentArr[$part])) {
                $parentArr[$part] = [];
            } elseif (!is_array($parentArr[$part])) {
                $parentArr[$part] = [];
            }
            $parentArr = &$parentArr[$part];
        }

        // Add the final part to the structure
        if (empty($parentArr[$leafPart])) {
            $parentArr[$leafPart] = $val;
        }
    }
    return $returnArr;
}

$fileTreeJson = getFileTree($filelist);
if ($type === "multi") {
    $fileTreeJson = [$dname => $fileTreeJson];
}

// then insert $fileTreeJson to database after json_encode
  • 前端 viewfilelist 优化,并提供折叠功能:
// 代码取自 OurBits /assets/js/common.js ,需要适配修改
function build_tree(tree,par = '') {
    let ret = '';
    for (let k in tree) {
        let v = tree[k];
        let dep = (par.match(/\//g) || []).length;
        if (typeof v == 'object') {
            ret += "<tr " +(par === "" ?  "" : "style='display:none' data-par = \"" + par + "\" ")+ "><td class='rowfollow' data-name='" + k + "'>" + "&ensp;".repeat(dep * 2) + "<a href='javascript: void(0);'><b>" + k +"</b></a></td>";
            ret += build_tree(v,par + "/" + k);
        } else {
            ret += "<tr " +(par === "" ?  "" : "style='display:none' data-par = \"" + par + "\" ")+"><td class=rowfollow data-name='" + k + "'>" + "&ensp;".repeat(dep * 2) + k + "</td><td class=rowfollow align='right' data-size='"+ v + "'>" + humanFileSize(v, 2) + "</td></tr>";
        }
    }
    return ret;
}

function viewfilelist(torrentid) {
    $.post('api.php', {'action': 'viewfiletree', 'tid': torrentid}, function (data) {
        if (data.success) {
            document.getElementById("showfl").style.display = 'none';
            document.getElementById("hidefl").style.display = 'block';
            var file_list = data.files;
            var file_list_html = "<table class=\"main\" border=\"1\" cellspacing=0 cellpadding=\"5\">";
            file_list_html += "<tr><td class=colhead>Path</td><td class=colhead align=center><img class=\"size\" src=\"../../pic/trans.gif\" alt=\"size\" /></td></tr>";
            file_list_html += build_tree(file_list);
            file_list_html += "</table>";
            document.getElementById("filelist").innerHTML = file_list_html;
            $('#filelist a').click(function () {
                let that = $(this);
                let parent = that.parents('tr:eq(0)');
                let par = parent.attr('data-par');
                let expand = (par ? par: "") + "/" + that.text();

                $('#filelist tr[data-par^="'+ expand +'/"]').hide();  // 首先隐藏所有对应子项
                $('#filelist tr[data-par$="'+ expand +'"]').toggle();  // 然后对当前项可见性进行切换
            })
        } else {
            alert(data.msg);
        }
    });
}
  • 提供平滑迁移功能(此处不做展示)

Rhilip avatar Sep 11 '21 11:09 Rhilip

感谢建议,优化部分延后一些。

xiaomlove avatar Jan 19 '22 11:01 xiaomlove

鉴于 Rhilip/Bencode 库的更新,建议直接使用其提供的 Rhilip\Bencode\TorrentFile 来替换整个种子解析过程。具体可见 https://github.com/Rhilip/NexusPHP/commit/346374e9836a049b4d6bbbd21f003560cb64642d

Rhilip avatar Mar 30 '22 04:03 Rhilip