-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathtable.go
126 lines (100 loc) · 2.1 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
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",
)
}
table.size = stat.Size() / int64(recordSize)
return table.size, nil
}