File size: 3,714 Bytes
84d2a97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use std::path::{Path, PathBuf};

use crate::operations::types::{CollectionError, CollectionResult};
use crate::shards::shard::ShardId;
use crate::shards::shard_config::{ShardConfig, ShardType};
use crate::shards::ShardVersion;

async fn shards_versions(
    collection_path: &Path,
    shard_id: ShardId,
) -> CollectionResult<Vec<(ShardVersion, PathBuf)>> {
    let mut entries = tokio::fs::read_dir(collection_path).await?;
    let mut all_versions: Vec<(ShardVersion, PathBuf)> = vec![];
    while let Some(entry) = entries.next_entry().await? {
        let path = entry.path();
        if path.is_dir() {
            let file_name_opt = path.file_name().and_then(|file_name| file_name.to_str());

            if file_name_opt.is_none() {
                continue;
            }

            let file_name = file_name_opt.unwrap();

            if file_name.starts_with(&format!("{shard_id}-")) {
                let version_opt = file_name
                    .split('-')
                    .nth(1)
                    .and_then(|version_str| version_str.parse::<ShardVersion>().ok());

                if version_opt.is_none() {
                    continue;
                }
                let version = version_opt.unwrap();
                all_versions.push((version, path.clone()));
            } else if file_name == format!("{shard_id}") {
                let version = 0;
                all_versions.push((version, path.clone()));
            }
        }
    }
    all_versions.sort_by_key(|(version, _)| *version);
    all_versions = all_versions.into_iter().rev().collect();
    Ok(all_versions)
}

pub fn versioned_shard_path(
    collection_path: &Path,
    shard_id: ShardId,
    version: ShardVersion,
) -> PathBuf {
    if version == 0 {
        collection_path.join(format!("{shard_id}"))
    } else {
        collection_path.join(format!("{shard_id}-{version}"))
    }
}

pub async fn latest_shard_paths(
    collection_path: &Path,
    shard_id: ShardId,
) -> CollectionResult<Vec<(PathBuf, ShardVersion, ShardType)>> {
    // Assume `all_versions` is sorted by version in descending order.
    let mut res = vec![];
    let mut seen_temp_shard = false;
    let all_versions = shards_versions(collection_path, shard_id).await?;
    for (version, path) in all_versions {
        let shard_config_opt = ShardConfig::load(&path)?;

        if let Some(shard_config) = shard_config_opt {
            match shard_config.r#type {
                ShardType::Local => {
                    res.push((path, version, shard_config.r#type));
                    break; // We don't need older local shards.
                }
                ShardType::Remote { .. } => {
                    res.push((path, version, shard_config.r#type));
                    break; // We don't need older remote shards.
                }
                ShardType::Temporary => {
                    if !seen_temp_shard {
                        res.push((path, version, shard_config.r#type));
                        seen_temp_shard = true;
                    }
                }
                ShardType::ReplicaSet => {
                    res.push((path, version, shard_config.r#type));
                    break; // We don't need older replica set shards.
                }
            }
        } else {
            log::warn!("Shard config not found for {}, skipping", path.display());
        }
    }
    if (seen_temp_shard && res.len() < 2) || res.is_empty() {
        return Err(CollectionError::service_error(format!(
            "No shard found: {shard_id} at {collection_path}",
            shard_id = shard_id,
            collection_path = collection_path.display()
        )));
    }
    Ok(res)
}