Skip to content

Commit 395d996

Browse files
committed
Test fixes
1 parent cce6f95 commit 395d996

File tree

3 files changed

+93
-54
lines changed

3 files changed

+93
-54
lines changed

src/Index.zig

+6
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ pub fn init(allocator: std.mem.Allocator, parent_dir: std.fs.Dir, path: []const
128128
}
129129

130130
pub fn deinit(self: *Self) void {
131+
log.info("closing index {}", .{@intFromPtr(self)});
131132
self.stopping.store(true, .release);
132133

133134
self.stopCheckpointThread();
@@ -229,6 +230,7 @@ fn doCheckpoint(self: *Self) !bool {
229230
}
230231

231232
fn checkpointThreadFn(self: *Self) void {
233+
log.debug("checkpoint thread started", .{});
232234
while (!self.stopping.load(.acquire)) {
233235
if (self.doCheckpoint()) |successful| {
234236
if (successful) {
@@ -238,8 +240,10 @@ fn checkpointThreadFn(self: *Self) void {
238240
} else |err| {
239241
log.err("checkpoint failed: {}", .{err});
240242
}
243+
log.debug("waiting for checkpoint event", .{});
241244
self.checkpoint_event.timedWait(std.time.ns_per_min) catch continue;
242245
}
246+
log.debug("checkpoint thread stopped", .{});
243247
}
244248

245249
fn startCheckpointThread(self: *Self) !void {
@@ -253,8 +257,10 @@ fn stopCheckpointThread(self: *Self) void {
253257
log.info("stopping checkpoint thread", .{});
254258
if (self.checkpoint_thread) |thread| {
255259
self.checkpoint_event.set();
260+
log.debug("waiting for checkpoint thread to exit", .{});
256261
thread.join();
257262
}
263+
log.debug("checkpoint thread stopped", .{});
258264
self.checkpoint_thread = null;
259265
}
260266

src/MultiIndex.zig

+14-19
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,14 @@ pub const IndexRef = struct {
2020
}
2121

2222
pub fn incRef(self: *IndexRef) void {
23-
self.lock.lock();
24-
defer self.lock.unlock();
25-
2623
self.references += 1;
2724
self.last_used_at = std.time.milliTimestamp();
2825
}
2926

3027
pub fn decRef(self: *IndexRef) bool {
31-
self.lock.lock();
32-
defer self.lock.unlock();
33-
3428
assert(self.references > 0);
3529
self.references -= 1;
36-
self.last_used_at = std.time.timestamp();
37-
30+
self.last_used_at = std.time.milliTimestamp();
3831
return self.references == 0;
3932
}
4033

@@ -119,17 +112,10 @@ fn removeIndex(self: *Self, name: []const u8) void {
119112
}
120113

121114
pub fn releaseIndex(self: *Self, index_ref: *IndexRef) void {
122-
if (index_ref.decRef()) {
123-
self.lock.lock();
124-
defer self.lock.unlock();
125-
126-
// index_ref.lock.lock();
127-
// defer index_ref.lock.unlock();
115+
self.lock.lock();
116+
defer self.lock.unlock();
128117

129-
// if (!index_ref.is_open) {
130-
// self.removeIndex(index_ref.name);
131-
// }
132-
}
118+
_ = index_ref.decRef();
133119
}
134120

135121
pub fn acquireIndex(self: *Self, name: []const u8) !*IndexRef {
@@ -170,20 +156,29 @@ pub fn getIndex(self: *Self, name: []const u8) !*IndexRef {
170156
}
171157

172158
pub fn createIndex(self: *Self, name: []const u8) !void {
159+
log.info("creating index {s}", .{name});
160+
173161
const index_ref = try self.acquireIndex(name);
174162
defer self.releaseIndex(index_ref);
175163

176164
try index_ref.ensureOpen(true);
177165
}
178166

179167
pub fn deleteIndex(self: *Self, name: []const u8) !void {
168+
log.info("deleting index {s}", .{name});
169+
180170
if (!isValidName(name)) {
181171
return error.InvalidIndexName;
182172
}
183173

184174
self.lock.lock();
185175
defer self.lock.unlock();
186176

187-
self.removeIndex(name);
177+
if (self.indexes.getEntry(name)) |entry| {
178+
entry.value_ptr.index.deinit();
179+
self.allocator.free(entry.key_ptr.*);
180+
self.indexes.removeByPtr(entry.key_ptr);
181+
}
182+
188183
try self.deleteIndexFiles(name);
189184
}

tests/conftest.py

+73-35
Original file line numberDiff line numberDiff line change
@@ -6,40 +6,62 @@
66
from urllib.parse import urljoin
77

88

9-
@pytest.fixture()
10-
def server_port():
11-
sock = socket.socket()
12-
sock.bind(('', 0))
13-
return sock.getsockname()[1]
9+
class ServerManager:
10+
11+
def __init__(self, base_dir, port):
12+
self.data_dir = base_dir / 'data'
13+
self.log_file = base_dir / 'server.log'
14+
self.port = port
15+
self.process = None
16+
17+
def start(self):
18+
command = [
19+
'valgrind',
20+
'zig-out/bin/fpindex',
21+
'--dir', str(self.data_dir),
22+
'--port', str(self.port),
23+
'--log-level', 'debug',
24+
]
25+
self.process = subprocess.Popen(
26+
command,
27+
stdin=subprocess.DEVNULL,
28+
stdout=subprocess.DEVNULL,
29+
stderr=self.log_file.open('w'),
30+
)
31+
32+
def stop(self):
33+
if self.process is not None:
34+
if self.process.returncode is None:
35+
self.process.terminate()
36+
try:
37+
self.process.wait(timeout=1.0)
38+
except subprocess.TimeoutExpired:
39+
self.process.kill()
40+
self.process.wait()
41+
42+
def error_log(self):
43+
for line in self.log_file.read_text().splitlines():
44+
yield line
45+
46+
47+
@pytest.fixture(scope='session')
48+
def server(tmp_path_factory):
49+
srv = ServerManager(base_dir=tmp_path_factory.mktemp('srv'), port=14502)
50+
srv.start()
51+
yield srv
52+
srv.stop()
53+
for line in srv.error_log():
54+
print(line)
1455

1556

16-
@pytest.fixture()
17-
def server(server_port, tmp_path):
18-
data_dir = tmp_path / 'data'
19-
stderr = tmp_path / 'server.stderr.log'
20-
command = [
21-
'zig-out/bin/fpindex',
22-
'--dir', str(data_dir),
23-
'--port', str(server_port),
24-
'--log-level', 'debug',
25-
]
26-
process = subprocess.Popen(
27-
command,
28-
stdin=subprocess.DEVNULL,
29-
stdout=subprocess.DEVNULL,
30-
stderr=stderr.open('w'),
31-
)
32-
yield
33-
if process.returncode is None:
34-
process.terminate()
35-
process.wait()
36-
for line in stderr.read_text().splitlines():
37-
print(line)
57+
index_no = 1
3858

3959

4060
@pytest.fixture
41-
def index_name():
42-
return 'testidx'
61+
def index_name(request):
62+
global index_no
63+
index_no += 1
64+
return f't{index_no:03d}'
4365

4466

4567
class Client:
@@ -48,18 +70,23 @@ def __init__(self, session, base_url):
4870
self.base_url = base_url
4971

5072
def head(self, url, **kwargs):
73+
kwargs.setdefault('timeout', 1)
5174
return self.session.head(urljoin(self.base_url, url), **kwargs)
5275

5376
def get(self, url, **kwargs):
77+
kwargs.setdefault('timeout', 1)
5478
return self.session.get(urljoin(self.base_url, url), **kwargs)
5579

5680
def put(self, url, **kwargs):
81+
kwargs.setdefault('timeout', 1)
5782
return self.session.put(urljoin(self.base_url, url), **kwargs)
5883

5984
def post(self, url, **kwargs):
85+
kwargs.setdefault('timeout', 1)
6086
return self.session.post(urljoin(self.base_url, url), **kwargs)
6187

6288
def delete(self, url, **kwargs):
89+
kwargs.setdefault('timeout', 1)
6390
return self.session.delete(urljoin(self.base_url, url), **kwargs)
6491

6592

@@ -74,17 +101,28 @@ def check_port(port_no):
74101
return sock.connect_ex(('127.0.0.1', port_no)) == 0
75102

76103

77-
@pytest.fixture
78-
def client(session, server_port, server):
79-
deadline = time.time() + 1
80-
while not check_port(server_port):
104+
def wait_for_ready(port, timeout):
105+
deadline = time.time() + timeout
106+
while not check_port(port):
81107
if time.time() > deadline:
82108
raise TimeoutError()
83-
time.sleep(0.01)
84-
return Client(session, f'http://localhost:{server_port}')
109+
time.sleep(timeout / 100.0)
110+
111+
112+
@pytest.fixture
113+
def client(session, server):
114+
wait_for_ready(server.port, 1)
115+
return Client(session, f'http://localhost:{server.port}')
85116

86117

87118
@pytest.fixture()
88119
def create_index(client, index_name):
89120
req = client.put(f'/{index_name}')
90121
req.raise_for_status()
122+
123+
124+
@pytest.fixture(autouse=True)
125+
def delete_index(client, index_name):
126+
yield
127+
req = client.delete(f'/{index_name}')
128+
req.raise_for_status()

0 commit comments

Comments
 (0)