forked from reconquest/shadowd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtable.go
127 lines (101 loc) · 2.15 KB
/
table.go
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package main
import (
"bufio"
"errors"
"fmt"
"os"
"github.com/reconquest/hierr-go"
)
type hashTable struct {
size int64
recordSize int
file *os.File
path string
}
func openHashTable(path string) (*hashTable, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
table := &hashTable{
file: file,
path: path,
}
return table, nil
}
func (table *hashTable) getRecord(number int64) ([]byte, error) {
recordSize, err := table.getRecordSize()
if err != nil {
return nil, hierr.Errorf(
err, "can't get table record size",
)
}
tableSize, err := table.getSize()
if err != nil {
return nil, hierr.Errorf(
err, "can't get table size",
)
}
if number >= tableSize {
return nil, errors.New("record number is out of range")
}
var (
// +1 for new line
offset = number * int64(recordSize+1)
record = make([]byte, recordSize)
)
readLength, err := table.file.ReadAt(record, offset)
if err != nil {
return nil, err
}
if readLength != recordSize {
return nil, errors.New("read bytes are less than required record size")
}
return record, nil
}
func (table *hashTable) hashExists(hash string) (bool, error) {
defer table.file.Seek(0, 0)
scanner := bufio.NewScanner(table.file)
for scanner.Scan() {
if scanner.Text() == hash {
return true, nil
}
}
return false, scanner.Err()
}
func (table *hashTable) getRecordSize() (int, error) {
if table.recordSize != 0 {
return table.recordSize, nil
}
var line string
_, err := fmt.Fscanln(table.file, &line)
if err != nil {
return 0, err
}
_, err = table.file.Seek(0, 0)
if err != nil {
return 0, err
}
table.recordSize = len(line)
return table.recordSize, nil
}
func (table *hashTable) getSize() (int64, error) {
if table.size != 0 {
return table.size, nil
}
recordSize, err := table.getRecordSize()
if err != nil {
return 0, hierr.Errorf(
err, "can't get table record size",
)
}
stat, err := os.Stat(table.path)
if err != nil {
return 0, hierr.Errorf(
err, "can't stat table file",
)
}
// +1 for new line symbol in the end of the line
table.size = stat.Size() / int64(recordSize+1)
return table.size, nil
}