Software /
code /
prosody
Comparison
util/datamanager.lua @ 13183:33b114fbb5de
util.datamanager: Add way to efficiently remove first items in a list
Copying data without parsing it should be more performant than parsing
it serializing back.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Wed, 12 Jul 2023 11:42:41 +0200 |
parent | 13182:c48ae06e24d6 |
child | 13185:b57f45165e1e |
comparison
equal
deleted
inserted
replaced
13182:c48ae06e24d6 | 13183:33b114fbb5de |
---|---|
504 return index, err; | 504 return index, err; |
505 end | 505 end |
506 return setmetatable({ file = file; index = index }, indexed_list_mt); | 506 return setmetatable({ file = file; index = index }, indexed_list_mt); |
507 end | 507 end |
508 | 508 |
509 local function shift_index(index_filename, index, trim_to, offset) | |
510 local index_scratch = index_filename .. "~"; | |
511 local new_index, err = io_open(index_scratch, "w"); | |
512 if not new_index then | |
513 os_remove(index_filename); | |
514 return "deleted", err; | |
515 end | |
516 | |
517 local ok, err = new_index:write(index_magic); | |
518 if not ok then | |
519 new_index:close(); | |
520 os_remove(index_filename); | |
521 os_remove(index_scratch); | |
522 return "deleted", err; | |
523 end | |
524 | |
525 if not index.file or not index.file:seek("set", index_item_size * trim_to) then | |
526 new_index:close(); | |
527 os_remove(index_filename); | |
528 os_remove(index_scratch); | |
529 return "deleted"; | |
530 else | |
531 local pack, unpack = string.pack, string.unpack; | |
532 for item in index.file:lines(index_item_size) do | |
533 local ok, err = new_index:write(pack(index_fmt, unpack(index_fmt, item) - offset)); | |
534 if not ok then | |
535 os_remove(index_filename); | |
536 os_remove(index_scratch); | |
537 return "deleted", err; | |
538 end | |
539 end | |
540 local ok, err = new_index:close(); | |
541 if not ok then | |
542 os_remove(index_filename); | |
543 os_remove(index_scratch); | |
544 return "deleted", err; | |
545 end | |
546 return os_rename(index_scratch, index_filename); | |
547 end | |
548 end | |
549 | |
550 local function list_shift(username, host, datastore, trim_to) | |
551 if trim_to == 1 then | |
552 return true | |
553 end | |
554 if type(trim_to) ~= "number" or trim_to < 1 then | |
555 return nil, "invalid-argument"; | |
556 end | |
557 local list_filename = getpath(username, host, datastore, "list"); | |
558 local index_filename = getpath(username, host, datastore, "lidx"); | |
559 local index, err = get_list_index(username, host, datastore); | |
560 if not index then | |
561 return nil, err; | |
562 end | |
563 | |
564 local new_first = index[trim_to]; | |
565 if not new_first then | |
566 os_remove(index_filename); | |
567 return os_remove(list_filename); | |
568 end | |
569 | |
570 local offset = new_first.start; | |
571 if offset == 0 then | |
572 return true; | |
573 end | |
574 | |
575 local r, err = io_open(list_filename, "r"); | |
576 if not r then | |
577 return nil, err; | |
578 end | |
579 local w, err = io_open(list_filename .. "~", "w"); | |
580 if not w then | |
581 return nil, err; | |
582 end | |
583 r:seek("set", offset); | |
584 for block in r:lines(0x1000) do | |
585 local ok, err = w:write(block); | |
586 if not ok then | |
587 return nil, err; | |
588 end | |
589 end | |
590 r:close(); | |
591 local ok, err = w:close(); | |
592 if not ok then | |
593 return nil, err; | |
594 end | |
595 shift_index(index_filename, index, trim_to, offset) | |
596 return os_rename(list_filename .. "~", list_filename); | |
597 end | |
598 | |
599 | |
509 local type_map = { | 600 local type_map = { |
510 keyval = "dat"; | 601 keyval = "dat"; |
511 list = "list"; | 602 list = "list"; |
512 } | 603 } |
513 | 604 |
607 path_decode = decode; | 698 path_decode = decode; |
608 path_encode = encode; | 699 path_encode = encode; |
609 | 700 |
610 build_list_index = build_list_index; | 701 build_list_index = build_list_index; |
611 list_open = list_open; | 702 list_open = list_open; |
703 list_shift = list_shift; | |
612 }; | 704 }; |