mirror of
https://github.com/zigzap/zap.git
synced 2025-10-20 15:14:08 +00:00
saner mem management, thread-safety
This commit is contained in:
parent
50c64e0f90
commit
1f8e8ac0e4
5 changed files with 107 additions and 38 deletions
|
@ -11,6 +11,9 @@ var alloc: std.mem.Allocator = undefined;
|
|||
var endpoint: zap.SimpleEndpoint = undefined;
|
||||
var users: Users = undefined;
|
||||
|
||||
// 100MB of json buffer
|
||||
var jsonbuf: [100 * 1024 * 1024]u8 = undefined;
|
||||
|
||||
pub fn init(
|
||||
a: std.mem.Allocator,
|
||||
user_path: []const u8,
|
||||
|
@ -53,7 +56,7 @@ fn getUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void {
|
|||
}
|
||||
if (userIdFromPath(path)) |id| {
|
||||
if (users.get(id)) |user| {
|
||||
if (zap.stringify(user, .{})) |json| {
|
||||
if (zap.stringifyBuf(&jsonbuf, user, .{})) |json| {
|
||||
_ = r.sendJson(json);
|
||||
}
|
||||
}
|
||||
|
@ -67,7 +70,7 @@ fn listUsers(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void {
|
|||
if (users.list(&l)) {} else |_| {
|
||||
return;
|
||||
}
|
||||
if (zap.stringifyArrayList(User, &l, .{})) |maybe_json| {
|
||||
if (zap.stringifyArrayListBuf(&jsonbuf, User, &l, .{})) |maybe_json| {
|
||||
if (maybe_json) |json| {
|
||||
_ = r.sendJson(json);
|
||||
}
|
||||
|
@ -88,7 +91,7 @@ fn postUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void {
|
|||
if (maybe_user) |u| {
|
||||
defer std.json.parseFree(User, u, .{ .allocator = alloc });
|
||||
if (users.addByName(u.first_name, u.last_name)) |id| {
|
||||
if (zap.stringify(.{ .status = "OK", .id = id }, .{})) |json| {
|
||||
if (zap.stringifyBuf(&jsonbuf, .{ .status = "OK", .id = id }, .{})) |json| {
|
||||
_ = r.sendJson(json);
|
||||
}
|
||||
} else |_| {
|
||||
|
@ -117,14 +120,14 @@ fn putUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void {
|
|||
.{ .allocator = alloc },
|
||||
);
|
||||
if (users.update(id, u.first_name, u.last_name)) {
|
||||
if (zap.stringify(.{
|
||||
if (zap.stringifyBuf(&jsonbuf, .{
|
||||
.status = "OK",
|
||||
.id = id,
|
||||
}, .{})) |json| {
|
||||
_ = r.sendJson(json);
|
||||
}
|
||||
} else {
|
||||
if (zap.stringify(.{
|
||||
if (zap.stringifyBuf(&jsonbuf, .{
|
||||
.status = "ERROR",
|
||||
.id = id,
|
||||
}, .{})) |json| {
|
||||
|
@ -143,11 +146,11 @@ fn deleteUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void {
|
|||
if (r.path) |path| {
|
||||
if (userIdFromPath(path)) |id| {
|
||||
if (users.delete(id)) {
|
||||
if (zap.stringify(.{ .status = "OK", .id = id }, .{})) |json| {
|
||||
if (zap.stringifyBuf(&jsonbuf, .{ .status = "OK", .id = id }, .{})) |json| {
|
||||
_ = r.sendJson(json);
|
||||
}
|
||||
} else {
|
||||
if (zap.stringify(.{
|
||||
if (zap.stringifyBuf(&jsonbuf, .{
|
||||
.status = "ERROR",
|
||||
.id = id,
|
||||
}, .{})) |json| {
|
||||
|
|
|
@ -3,7 +3,10 @@ const zap = @import("zap");
|
|||
const Endpoint = @import("endpoint.zig");
|
||||
|
||||
pub fn main() !void {
|
||||
const allocator = std.heap.page_allocator;
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{
|
||||
.thread_safe = true,
|
||||
}){};
|
||||
var allocator = gpa.allocator();
|
||||
// setup listener
|
||||
var listener = zap.SimpleEndpointListener.init(
|
||||
allocator,
|
||||
|
|
|
@ -32,10 +32,7 @@ pub fn init(a: std.mem.Allocator) Self {
|
|||
// the request will be freed (and its mem reused by facilio) when it's
|
||||
// completed, so we take copies of the names
|
||||
pub fn addByName(self: *Self, first: ?[]const u8, last: ?[]const u8) !usize {
|
||||
// TODO: get rid of the temp allocation here
|
||||
var temp = try self.alloc.alloc(InternalUser, 1);
|
||||
defer self.alloc.free(temp);
|
||||
var user = temp[0];
|
||||
var user: InternalUser = undefined;
|
||||
user.firstnamelen = 0;
|
||||
user.lastnamelen = 0;
|
||||
if (first) |firstname| {
|
||||
|
@ -66,7 +63,7 @@ pub fn delete(self: *Self, id: usize) bool {
|
|||
pub fn get(self: *Self, id: usize) ?User {
|
||||
// we don't care about locking here, as our usage-pattern is unlikely to
|
||||
// get a user by id that is not known yet
|
||||
if (self.users.get(id)) |pUser| {
|
||||
if (self.users.getPtr(id)) |pUser| {
|
||||
return .{
|
||||
.id = pUser.id,
|
||||
.first_name = pUser.firstnamebuf[0..pUser.firstnamelen],
|
||||
|
@ -83,11 +80,9 @@ pub fn update(
|
|||
last: ?[]const u8,
|
||||
) bool {
|
||||
// we don't care about locking here
|
||||
var user: ?InternalUser = self.users.get(id);
|
||||
// we got a copy apparently, so we need to put again
|
||||
if (user) |*pUser| {
|
||||
pUser.*.firstnamelen = 0;
|
||||
pUser.*.lastnamelen = 0;
|
||||
if (self.users.getPtr(id)) |pUser| {
|
||||
pUser.firstnamelen = 0;
|
||||
pUser.lastnamelen = 0;
|
||||
if (first) |firstname| {
|
||||
std.mem.copy(u8, pUser.firstnamebuf[0..], firstname);
|
||||
pUser.firstnamelen = firstname.len;
|
||||
|
@ -96,12 +91,6 @@ pub fn update(
|
|||
std.mem.copy(u8, pUser.lastnamebuf[0..], lastname);
|
||||
pUser.lastnamelen = lastname.len;
|
||||
}
|
||||
_ = self.users.remove(id);
|
||||
if (self.users.put(id, pUser.*)) {
|
||||
return true;
|
||||
} else |_| {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -18,8 +18,9 @@ fn on_request(r: zap.SimpleRequest) void {
|
|||
const user_id: usize = @intCast(usize, the_path[6] - 0x30);
|
||||
const user = users.get(user_id);
|
||||
|
||||
var buf: [100]u8 = undefined;
|
||||
var json_to_send: []const u8 = undefined;
|
||||
if (stringify(user, .{})) |json| {
|
||||
if (zap.stringifyBuf(&buf, user, .{})) |json| {
|
||||
json_to_send = json;
|
||||
} else {
|
||||
json_to_send = "null";
|
||||
|
@ -39,17 +40,6 @@ fn setupUserData(a: std.mem.Allocator) !void {
|
|||
try users.put(2, .{ .first_name = "Your", .last_name = "Mom" });
|
||||
}
|
||||
|
||||
var buf: [100]u8 = undefined;
|
||||
fn stringify(value: anytype, options: std.json.StringifyOptions) ?[]const u8 {
|
||||
var fba = std.heap.FixedBufferAllocator.init(&buf);
|
||||
var string = std.ArrayList(u8).init(fba.allocator());
|
||||
if (std.json.stringify(value, options, string.writer())) {
|
||||
return string.items;
|
||||
} else |_| { // error
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
var a = std.heap.page_allocator;
|
||||
try setupUserData(a);
|
||||
|
|
88
src/util.zig
88
src/util.zig
|
@ -6,8 +6,15 @@ const std = @import("std");
|
|||
|
||||
// 1MB JSON buffer
|
||||
var jsonbuf: [1024 * 1024]u8 = undefined;
|
||||
var mutex: std.Thread.Mutex = .{};
|
||||
|
||||
pub fn stringify(value: anytype, options: std.json.StringifyOptions) ?[]const u8 {
|
||||
/// use default 1MB buffer, mutex-protected
|
||||
pub fn stringify(
|
||||
value: anytype,
|
||||
options: std.json.StringifyOptions,
|
||||
) ?[]const u8 {
|
||||
mutex.lock();
|
||||
defer mutex.unlock();
|
||||
var fba = std.heap.FixedBufferAllocator.init(&jsonbuf);
|
||||
var string = std.ArrayList(u8).init(fba.allocator());
|
||||
if (std.json.stringify(value, options, string.writer())) {
|
||||
|
@ -17,7 +24,14 @@ pub fn stringify(value: anytype, options: std.json.StringifyOptions) ?[]const u8
|
|||
}
|
||||
}
|
||||
|
||||
pub fn stringifyArrayList(comptime T: anytype, list: *std.ArrayList(T), options: std.json.StringifyOptions) !?[]const u8 {
|
||||
/// use default 1MB buffer, mutex-protected
|
||||
pub fn stringifyArrayList(
|
||||
comptime T: anytype,
|
||||
list: *std.ArrayList(T),
|
||||
options: std.json.StringifyOptions,
|
||||
) !?[]const u8 {
|
||||
mutex.lock();
|
||||
defer mutex.unlock();
|
||||
var fba = std.heap.FixedBufferAllocator.init(&jsonbuf);
|
||||
var string = std.ArrayList(u8).init(fba.allocator());
|
||||
var writer = string.writer();
|
||||
|
@ -31,3 +45,73 @@ pub fn stringifyArrayList(comptime T: anytype, list: *std.ArrayList(T), options:
|
|||
try writer.writeByte(']');
|
||||
return string.items;
|
||||
}
|
||||
|
||||
/// provide your own buf, NOT mutex-protected!
|
||||
pub fn stringifyBuf(
|
||||
buffer: []u8,
|
||||
value: anytype,
|
||||
options: std.json.StringifyOptions,
|
||||
) ?[]const u8 {
|
||||
var fba = std.heap.FixedBufferAllocator.init(buffer);
|
||||
var string = std.ArrayList(u8).init(fba.allocator());
|
||||
if (std.json.stringify(value, options, string.writer())) {
|
||||
return string.items;
|
||||
} else |_| { // error
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// provide your own buf, NOT mutex-protected
|
||||
pub fn stringifyArrayListBuf(
|
||||
buffer: []u8,
|
||||
comptime T: anytype,
|
||||
list: *std.ArrayList(T),
|
||||
options: std.json.StringifyOptions,
|
||||
) !?[]const u8 {
|
||||
var fba = std.heap.FixedBufferAllocator.init(buffer);
|
||||
var string = std.ArrayList(u8).init(fba.allocator());
|
||||
var writer = string.writer();
|
||||
try writer.writeByte('[');
|
||||
var first: bool = true;
|
||||
for (list.items) |user| {
|
||||
if (!first) try writer.writeByte(',');
|
||||
first = false;
|
||||
try std.json.stringify(user, options, string.writer());
|
||||
}
|
||||
try writer.writeByte(']');
|
||||
return string.items;
|
||||
}
|
||||
|
||||
/// provide your own allocator, NOT mutex-protected
|
||||
pub fn stringifyAlloc(
|
||||
a: std.mem.Allocator,
|
||||
value: anytype,
|
||||
options: std.json.StringifyOptions,
|
||||
) ?[]const u8 {
|
||||
var string = std.ArrayList(u8).init(a);
|
||||
if (std.json.stringify(value, options, string.writer())) {
|
||||
return string.items;
|
||||
} else |_| { // error
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// provide your own allocator, NOT mutex-protected
|
||||
pub fn stringifyArrayListAlloc(
|
||||
a: std.mem.Allocator,
|
||||
comptime T: anytype,
|
||||
list: *std.ArrayList(T),
|
||||
options: std.json.StringifyOptions,
|
||||
) !?[]const u8 {
|
||||
var string = std.ArrayList(u8).init(a);
|
||||
var writer = string.writer();
|
||||
try writer.writeByte('[');
|
||||
var first: bool = true;
|
||||
for (list.items) |user| {
|
||||
if (!first) try writer.writeByte(',');
|
||||
first = false;
|
||||
try std.json.stringify(user, options, string.writer());
|
||||
}
|
||||
try writer.writeByte(']');
|
||||
return string.items;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue