Avoid allocating tag names in a loop
Diff
src/git.rs | 3 +--
src/database/schema/commit.rs | 2 +-
src/database/schema/tag.rs | 17 +++++++++++++++--
src/methods/repo/mod.rs | 3 ++-
src/methods/repo/refs.rs | 23 ++++++++++++++++++-----
templates/repo/macros/refs.html | 4 ++--
6 files changed, 31 insertions(+), 21 deletions(-)
@@ -216,8 +216,7 @@
while let Ok(Some(Ok(item))) = object
.try_into_tree()
.iter()
.map(gix::Tree::iter)
.flatten()
.flat_map(gix::Tree::iter)
.at_most_one()
{
let nested_object = item.object().context(
@@ -166,7 +166,7 @@
};
Yoke::try_attach_to_cart(Box::from(value), |value| {
rkyv::access::<_, rkyv::rancor::Error>(&value)
rkyv::access::<_, rkyv::rancor::Error>(value)
})
.context("Failed to deserialize commit")
.map(Some)
@@ -34,6 +34,7 @@
prefix: RepositoryId,
}
pub type YokedString = Yoked<&'static str>;
pub type YokedTag = Yoked<&'static <Tag as Archive>::Archived>;
impl TagTree {
@@ -88,7 +89,7 @@
.collect())
}
pub fn fetch_all(&self) -> anyhow::Result<Vec<(String, YokedTag)>> {
pub fn fetch_all(&self) -> anyhow::Result<Vec<(YokedString, YokedTag)>> {
let cf = self
.db
.cf_handle(TAG_FAMILY)
@@ -99,9 +100,15 @@
.prefix_iterator_cf(cf, self.prefix.to_be_bytes())
.filter_map(Result::ok)
.filter_map(|(name, value)| {
let name = String::from_utf8_lossy(name.strip_prefix(&self.prefix.to_be_bytes())?)
.strip_prefix("refs/tags/")?
.to_string();
let name = Yoke::try_attach_to_cart(name, |data| {
let data = data
.strip_prefix(&self.prefix.to_be_bytes())
.ok_or(())?
.strip_prefix(b"refs/tags/")
.ok_or(())?;
simdutf8::basic::from_utf8(data).map_err(|_| ())
})
.ok()?;
Some((name, value))
})
@@ -111,7 +118,7 @@
})?;
Ok((name, value))
})
.collect::<anyhow::Result<Vec<(String, YokedTag)>>>()?;
.collect::<anyhow::Result<Vec<(YokedString, YokedTag)>>>()?;
res.sort_unstable_by(|a, b| {
let a_tagger = a.1.get().tagger.as_ref().map(ArchivedAuthor::time);
@@ -37,6 +37,7 @@
tag::handle as handle_tag,
tree::handle as handle_tree,
};
use crate::database::schema::tag::YokedString;
use crate::{
database::schema::{commit::YokedCommit, tag::YokedTag},
layers::UnwrapInfallible,
@@ -192,5 +193,5 @@
pub struct Refs {
heads: BTreeMap<String, YokedCommit>,
tags: Vec<(String, YokedTag)>,
tags: Vec<(YokedString, YokedTag)>,
}
@@ -1,10 +1,5 @@
use std::{collections::BTreeMap, sync::Arc};
use anyhow::Context;
use askama::Template;
use axum::{response::IntoResponse, Extension};
use rkyv::string::ArchivedString;
use crate::{
into_response,
methods::{
@@ -12,6 +7,11 @@
repo::{Refs, Repository, Result},
},
};
use anyhow::Context;
use askama::Template;
use axum::{response::IntoResponse, Extension};
use rkyv::string::ArchivedString;
use yoke::Yoke;
#[derive(Template)]
#[template(path = "repo/refs.html")]
@@ -28,17 +28,20 @@
tokio::task::spawn_blocking(move || {
let repository = crate::database::schema::repository::Repository::open(&db, &*repo)?
.context("Repository does not exist")?;
let repository = repository.get();
let heads_db = repository.heads(&db)?;
let heads_db = heads_db.as_ref().map(Yoke::get);
let mut heads = BTreeMap::new();
if let Some(heads_db) = repository.get().heads(&db)? {
for head in heads_db
.get()
if let Some(archived_heads) = heads_db {
for head in archived_heads
.0
.as_slice()
.iter()
.map(ArchivedString::as_str)
{
let commit_tree = repository.get().commit_tree(db.clone(), head);
let commit_tree = repository.commit_tree(db.clone(), head);
let name = head.strip_prefix("refs/heads/");
if let (Some(name), Some(commit)) = (name, commit_tree.fetch_latest_one()?) {
@@ -47,7 +50,7 @@
}
}
let tags = repository.get().tag_tree(db).fetch_all()?;
let tags = repository.tag_tree(db).fetch_all()?;
Ok(into_response(View {
repo,
@@ -40,8 +40,8 @@
<tbody>
{% for (name, tag) in tags -%}
<tr>
<td><a href="/{{ repo.display() }}/tag/?h={{ name }}">{{- name -}}</a></td>
<td><a href="/{{ repo.display() }}/snapshot?h={{ name }}">{{- name -}}.tar.gz</a></td>
<td><a href="/{{ repo.display() }}/tag/?h={{ name.get() }}">{{- name.get() -}}</a></td>
<td><a href="/{{ repo.display() }}/snapshot?h={{ name.get() }}">{{- name.get() -}}.tar.gz</a></td>
<td>
{% if let Some(tagger) = tag.get().tagger.as_ref() -%}
<img src="{{ tagger.email|gravatar }}" width="13" height="13">