1 module neton.snap.SnapShotter;
2 
3 import std.stdio;
4 import std.file;
5 import std.path;
6 import std.array;
7 import std.format;
8 
9 // import protocol.Msg;
10 import hunt.util.Serialize;
11 import hunt.logging;
12 import std.algorithm.sorting;
13 
14 // import raft.Node;
15 import hunt.raft;
16 
17 const string snapSuffix = ".snap";
18 
19 const string ErrNoSnapshot = "snap: no available snapshot";
20 const string ErrEmptySnapshot = "snap: empty snapshot";
21 const string ErrCRCMismatch = "snap: crc mismatch";
22 
23 // struct  SnapData {
24 // 	string data;
25 // }
26 
27 class Snapshotter
28 {
29     string _dir;
30 
31     struct snapName
32     {
33         int term;
34         int index;
35     }
36 
37     this(string dir)
38     {
39         _dir = dir;
40     }
41 
42     void SaveSnap(Snapshot snapshot)
43     {
44         if (IsEmptySnap(snapshot))
45             return;
46         auto writer = appender!string();
47         formattedWrite(writer, "%s/%s-%s%s", _dir, snapshot.Metadata.Term,
48                 snapshot.Metadata.Index, snapSuffix);
49         logInfo("savesnap file name : ", writer.data);
50         auto b = serialize(snapshot);
51         auto file = File(writer.data, "wb");
52         file.rawWrite(b);
53         file.close();
54 
55         auto snaps = snapNames();
56         foreach (snap; snaps)
57         {
58             auto filepath = _dir ~ "/" ~ snap;
59             if (filepath != writer.data)
60             {
61                 remove(filepath);
62             }
63         }
64     }
65 
66     Snapshot loadSnap()
67     {
68         Snapshot snapshot;
69         string lastName = getLastSnapName();
70         if (lastName is null)
71         {
72             logInfo("-------- no snap shot info ");
73             return snapshot;
74         }
75         auto file = File(lastName, "rb");
76         byte[] content;
77         byte[] data = new byte[1024];
78         while (!file.eof())
79         {
80             content ~= file.rawRead(data);
81         }
82         file.close();
83         snapshot = unserialize!Snapshot(content);
84         return snapshot;
85     }
86 
87     string[] snapNames()
88     {
89         string[] names;
90 
91         foreach (string name; dirEntries(_dir, SpanMode.shallow))
92         {
93             names ~= std.path.baseName(name);
94         }
95         return names;
96     }
97 
98     string getLastSnapName()
99     {
100         string[] names = snapNames();
101         if (names.length == 0)
102             return string.init;
103         snapName[] snap;
104         foreach (string name; names)
105         {
106             int term, index;
107             formattedRead(name, "%s-%s.snap", &term, &index);
108 
109             snap ~= snapName(term, index);
110         }
111 
112         multiSort!("a.term > b.term", "a.index > b.index")(snap);
113         logInfo("last snap shot ,term : ", snap[0].term, " index : ", snap[0].index);
114         auto lastName = appender!string();
115         formattedWrite(lastName, "%s/%s-%s%s", _dir, snap[0].term, snap[0].index, snapSuffix);
116         return lastName.data;
117     }
118 }