0 | ||| Log-Structured Merge RRB Vector Internals
35 | %hide Control.Monad.Elin.Elin.(.run)
36 | %hide Control.Monad.Elin.Elin.run
37 | %hide Prelude.null
38 | %hide Prelude.Ops.infixr.(<|)
39 | %hide Prelude.Ops.infixl.(|>)
43 | --------------------------------------------------------------------------------
44 | -- Buffer Utilities
45 | --------------------------------------------------------------------------------
47 | ||| Empty mutation buffer.
48 | |||
49 | export
54 | --------------------------------------------------------------------------------
55 | -- Write Buffer Utilities
56 | --------------------------------------------------------------------------------
58 | ||| Empty buffer state.
59 | |||
60 | export
65 | --------------------------------------------------------------------------------
66 | -- Thread Context Utilities
67 | --------------------------------------------------------------------------------
69 | ||| Determines whether a buffer contains pending entries.
70 | |||
71 | ||| Returns:
72 | ||| - True when no buffered operations exist.
73 | ||| - False otherwise.
74 | |||
75 | ||| Properties:
76 | ||| - O(1).
77 | |||
78 | export
84 | ||| Determines whether a thread context contains buffered work.
85 | |||
86 | ||| Returns:
87 | ||| - True when all thread-local mutation state is empty.
88 | ||| - False otherwise.
89 | |||
90 | ||| Properties:
91 | ||| - O(1).
92 | |||
93 | ||| Notes:
94 | ||| - Sequence numbers are ignored.
95 | ||| - Historical sequence advancement does not imply pending work.
96 | |||
97 | export
103 | --------------------------------------------------------------------------------
104 | -- Metrics Utilities
105 | --------------------------------------------------------------------------------
107 | ||| Empty rebuild metrics.
108 | |||
109 | ||| Properties:
110 | ||| - No rebuilds observed.
111 | ||| - Average batch size is effectively zero.
112 | |||
113 | export
116 | MkRebuildMetrics
117 | 0
118 | 0
119 | 0
121 | --------------------------------------------------------------------------------
122 | -- Rebuild Service Utilities
123 | --------------------------------------------------------------------------------
125 | ||| Initial rebuild service state.
126 | |||
127 | ||| Properties:
128 | ||| - Service begins idle.
129 | ||| - No rebuild failures recorded.
130 | |||
131 | export
134 | MkRebuildServiceState
135 | Sleeping
136 | initialRebuildMetrics
138 | --------------------------------------------------------------------------------
139 | -- Metrics
140 | --------------------------------------------------------------------------------
142 | ||| Updates rebuild metrics after a successful rebuild cycle.
143 | |||
144 | ||| Parameters:
145 | ||| - batchsize: Number of entries processed in this cycle.
146 | |||
147 | ||| Properties:
148 | ||| - O(1).
149 | ||| - Pure deterministic update.
150 | |||
151 | export
161 | ||| Computes average rebuild batch size.
162 | |||
163 | ||| Returns:
164 | ||| - 0 when no rebuilds have occurred.
165 | |||
166 | export
172 | 0
176 | --------------------------------------------------------------------------------
177 | -- Registering Threads
178 | --------------------------------------------------------------------------------
180 | ||| Registers a thread if necessary and returns its thread context.
181 | |||
182 | ||| Behavior:
183 | ||| - Existing registrations are reused.
184 | ||| - Missing registrations allocate fresh thread state.
185 | |||
186 | ||| Properties:
187 | ||| - One ThreadContext per ThreadId.
188 | ||| - Preserves existing mutation state.
189 | |||
190 | export
201 | tid
202 | 0
203 | emptyWriteBuffers
205 | )
207 | --------------------------------------------------------------------------------
208 | -- Generation Utilities
209 | --------------------------------------------------------------------------------
211 | ||| Announces that a thread has entered a snapshot read section.
212 | |||
213 | ||| Behavior:
214 | ||| - Registers the generation currently being read.
215 | ||| - Replaces any previous generation announcement.
216 | |||
217 | ||| Properties:
218 | ||| - O(log n).
219 | ||| - One active generation per thread.
220 | ||| - Used by reclamation safety checks.
221 | |||
222 | export
231 | )
232 | )
234 | ||| Announces that a thread has completed a snapshot read section.
235 | |||
236 | ||| Behavior:
237 | ||| - Removes thread participation state.
238 | ||| - Indicates thread no longer references a snapshot.
239 | |||
240 | ||| Properties:
241 | ||| - O(log n).
242 | ||| - Enables reclamation progress.
243 | |||
244 | export
252 | )
254 | ||| Finds oldest active generation.
255 | |||
256 | ||| Returns:
257 | ||| - Nothing when no readers exist.
258 | ||| - Just generation otherwise.
259 | |||
260 | ||| Properties:
261 | ||| - O(n).
262 | |||
263 | export
269 | Nothing
273 | --------------------------------------------------------------------------------
274 | -- Mutation Utilities
275 | --------------------------------------------------------------------------------
277 | ||| Appends an Entry onto the end of a mutation buffer.
278 | |||
279 | ||| Properties:
280 | ||| - O(1).
281 | ||| - Preserves insertion ordering.
282 | |||
283 | export
290 | ||| Appends a deferred mutation into the active write buffer.
291 | |||
292 | ||| Properties:
293 | ||| - Frozen buffer remains unchanged.
294 | ||| - O(1) amortized.
295 | |||
296 | export
301 | MkWriteBuffers
304 | ||| Converts an operation into an Entry and appends it into the owning thread's active mutation buffer.
305 | |||
306 | ||| Steps:
307 | ||| - Acquire current timestamp.
308 | ||| - Register thread if necessary.
309 | ||| - Allocate Entry.
310 | ||| - Increment sequence counter.
311 | ||| - Append into active write buffer.
312 | ||| - Increment global write pressure.
313 | ||| - Mark rebuild work as pending.
314 | |||
315 | ||| Properties:
316 | ||| - O(log n) registry update.
317 | ||| - O(1) buffer append.
318 | ||| - Deterministic replay ordering.
319 | ||| - Adaptive batching pressure is globally visible atomically.
320 | |||
321 | export
336 | op
337 | now'
338 | tid
344 | )
352 | )
353 | where
357 | --------------------------------------------------------------------------------
358 | -- Rebuild Trigger
359 | --------------------------------------------------------------------------------
361 | ||| Sends a rebuild notification to the background rebuilder.
362 | |||
363 | ||| Behavior:
364 | ||| - Requests background progression toward snapshot publication.
365 | ||| - Multiple requests may be coalesced.
366 | ||| - Triggering occurs only after adaptive batching thresholds indicate sufficient accumulated write pressure.
367 | |||
368 | ||| Notes:
369 | ||| - Does not guarantee immediate rebuild execution.
370 | ||| - Does not guarantee publication.
371 | |||
372 | export
383 | )
390 | --------------------------------------------------------------------------------
391 | -- Scheduling Helper
392 | --------------------------------------------------------------------------------
394 | ||| Schedules rebuild work if adaptive batching has reached its target.
395 | |||
396 | ||| Behavior:
397 | ||| - Checks whether the current write accumulation has crossed the adaptive batch threshold.
398 | ||| - Coalesces multiple concurrent scheduling attempts.
399 | |||
400 | ||| Properties:
401 | ||| - O(1).
402 | ||| - Avoids duplicate rebuild requests.
403 | |||
404 | export
416 | --------------------------------------------------------------------------------
417 | -- Buffer Rotation
418 | --------------------------------------------------------------------------------
420 | ||| Extract active buffer ownership for rebuilding.
421 | |||
422 | ||| Returns:
423 | ||| - Updated thread context with empty active buffer
424 | ||| - Extracted buffer now owned by rebuilder
425 | |||
426 | export
432 | MkWriteBuffers
433 | emptyBuffer
437 | --------------------------------------------------------------------------------
438 | -- Registry Rotation
439 | --------------------------------------------------------------------------------
441 | ||| Atomically extracts active buffers from all registered threads.
442 | |||
443 | ||| Behavior:
444 | ||| - Replaces active buffers with empty buffers.
445 | ||| - Transfers ownership of previous active buffers.
446 | ||| - Removes thread registrations whose post-rotation state contains no pending work.
447 | |||
448 | ||| Lifecycle:
449 | ||| - Rotated thread contexts whose active buffer becomes empty are removed.
450 | ||| - Because only active buffers contribute to emptiness, rebuild currently removes all rotated thread registrations.
451 | ||| - Explicit thread unregistration is unnecessary.
452 | |||
453 | ||| Properties:
454 | ||| - Extracted entries appear exactly once.
455 | ||| - Prevents unbounded registry growth.
456 | ||| - O(number of registered threads).
457 | |||
458 | export
471 | acc
474 | )
475 | Data.SortedMap.empty
478 | )
480 | --------------------------------------------------------------------------------
481 | -- Entry Collection
482 | --------------------------------------------------------------------------------
484 | ||| Converts a buffer into a list of contained entries.
485 | |||
486 | ||| Behavior:
487 | ||| - Preserves insertion order.
488 | ||| - Extracts buffered mutation events for rebuild processing.
489 | |||
490 | ||| Properties:
491 | ||| - O(n).
492 | ||| - Does not modify buffer ownership.
493 | ||| - Pure projection operation.
494 | |||
495 | ||| Notes:
496 | ||| - Intended for rebuild entry collection.
497 | |||
498 | export
504 | ||| Collects entries from multiple extracted buffers.
505 | |||
506 | ||| Behavior:
507 | ||| - Traverses all buffers.
508 | ||| - Concatenates their entries into a single list.
509 | |||
510 | ||| Properties:
511 | ||| - O(total entries).
512 | ||| - Preserves per-buffer ordering.
513 | ||| - Does not perform global ordering.
514 | |||
515 | ||| Notes:
516 | ||| - Intended as a preprocessing step before sorting.
517 | |||
518 | export
524 | ||| Produces a deterministic global ordering of buffered entries.
525 | |||
526 | ||| Ordering:
527 | ||| - timestamp
528 | ||| - thread id
529 | ||| - sequence number
530 | |||
531 | ||| Properties:
532 | ||| - O(n log n).
533 | ||| - Deterministic across rebuild cycles.
534 | |||
535 | ||| Notes:
536 | ||| - Required before replay to ensure stable behavior under concurrent writes.
537 | |||
538 | export
543 | sort
545 | --------------------------------------------------------------------------------
546 | -- Replay
547 | --------------------------------------------------------------------------------
549 | ||| Applies a single deferred mutation to an RRBVector snapshot.
550 | |||
551 | ||| Behavior:
552 | ||| - Executes the logical operation represented by Operation.
553 | ||| - Produces a new immutable vector.
554 | ||| - Does not mutate the supplied vector.
555 | |||
556 | ||| Variants:
557 | ||| - Append -> append value to end
558 | ||| - Prepend -> prepend value to beginning
559 | ||| - Insert -> insert value at index
560 | ||| - Delete -> remove value at index
561 | ||| - Update -> replace value at index
562 | |||
563 | ||| Properties:
564 | ||| - Pure.
565 | ||| - Deterministic.
566 | ||| - Preserves RRBVector immutability.
567 | |||
568 | ||| Notes:
569 | ||| - Bounds behavior is inherited from the underlying RRBVector operation.
570 | |||
571 | export
586 | ||| Replays a sequence of buffered mutations onto an immutable snapshot.
587 | |||
588 | ||| Behavior:
589 | ||| - Traverses entries in order.
590 | ||| - Applies each contained operation to the accumulating vector.
591 | ||| - Produces a rebuilt snapshot reflecting all replayed mutations.
592 | |||
593 | ||| Ordering:
594 | ||| - Replay order is exactly the order of the supplied entry list.
595 | ||| - Deterministic replay therefore depends on prior sorting.
596 | |||
597 | ||| Properties:
598 | ||| - Pure.
599 | ||| - O(number of entries × operation cost).
600 | ||| - Preserves snapshot immutability.
601 | |||
602 | ||| Notes:
603 | ||| - Typically executed after collectEntries and sortEntries.
604 | ||| - Does not validate entry ordering.
605 | |||
606 | export
613 | --------------------------------------------------------------------------------
614 | -- Reading
615 | --------------------------------------------------------------------------------
617 | ||| Reads the current immutable snapshot together with its generation.
618 | |||
619 | ||| Behavior:
620 | ||| - Atomically captures the current SnapshotState.
621 | ||| - Registers the thread as an active reader of that generation.
622 | ||| - Passes (generation, snapshot tree) to the user function.
623 | ||| - Ensures reader registration is cleaned up after evaluation.
624 | |||
625 | ||| Key property:
626 | ||| - The generation and tree are consistent and taken from the same CAS snapshot.
627 | |||
628 | ||| This enables:
629 | ||| - Precise visibility reasoning.
630 | ||| - Safe interaction with reclamation.
631 | ||| - Deterministic debugging of snapshot lag.
632 | |||
633 | ||| Complexity:
634 | ||| - O(log n) for reader registration/removal.
635 | ||| - O(1) snapshot access.
636 | |||
637 | export
649 | where
666 | --------------------------------------------------------------------------------
667 | -- Metrics Queries
668 | --------------------------------------------------------------------------------
670 | ||| Returns current rebuild metrics.
671 | |||
672 | ||| Properties:
673 | ||| - O(1)
674 | ||| - Snapshot of current service state
675 | |||
676 | export
682 | ||| Returns average rebuild batch size.
683 | |||
684 | ||| Properties:
685 | ||| - O(1)
686 | |||
687 | export
693 | --------------------------------------------------------------------------------
694 | -- Adaptive Batching
695 | --------------------------------------------------------------------------------
697 | ||| Adjusts adaptive batching window according to observed write pressure.
698 | |||
699 | ||| Rules:
700 | ||| - Pressure above the current window expands the window.
701 | ||| - Pressure below half the current window shrinks the window.
702 | ||| - Window never shrinks below 1.
703 | |||
704 | ||| Properties:
705 | ||| - Pure deterministic policy function.
706 | ||| - Does not affect correctness.
707 | ||| - Only influences rebuild batching behavior.
708 | |||
709 | export
722 | window
724 | --------------------------------------------------------------------------------
725 | -- Publication
726 | --------------------------------------------------------------------------------
728 | ||| Atomically publishes a rebuilt snapshot and advances adaptive batching state.
729 | |||
730 | ||| Steps:
731 | ||| - Publish rebuilt immutable tree.
732 | ||| - Increment snapshot generation.
733 | ||| - Retire previous snapshot.
734 | ||| - Reset accumulated write pressure.
735 | ||| - Clear rebuild pending state.
736 | ||| - Adaptively adjust batching window.
737 | |||
738 | ||| Properties:
739 | ||| - Snapshot publication is atomic.
740 | ||| - Readers always observe a consistent snapshot/generation pair.
741 | ||| - Adaptive batching state transitions are globally visible atomically.
742 | ||| - Previous snapshots become eligible for reclamation.
743 | |||
744 | ||| Notes:
745 | ||| - Adaptive batching decisions are based on write pressure observed since the previous successful publication.
746 | |||
747 | export
752 | update combinedsnapshotstateref (\(MkCombinedSnapshotState snapshot retired readers writepressure rebuildpending batchwindow) =>
760 | )
761 | )
763 | --------------------------------------------------------------------------------
764 | -- Reclamation Utilities
765 | --------------------------------------------------------------------------------
767 | ||| Computes the newest retired generation that may safely be reclaimed.
768 | |||
769 | ||| Behavior:
770 | ||| - Determines the oldest snapshot generation currently referenced by active readers.
771 | ||| - Finds the highest retired generation strictly older than that reader boundary.
772 | ||| - Returns Nothing when no reclaimable generation exists.
773 | |||
774 | ||| Returns:
775 | ||| - Nothing: No readers exist, or no retired snapshots can be reclaimed.
776 | ||| - Just g: Every retired snapshot with generation <= g may safely be reclaimed.
777 | |||
778 | ||| Safety rules:
779 | ||| - Readers observing generation G may still require snapshot G.
780 | ||| - Readers may also require all newer generations.
781 | ||| - Only snapshots strictly older than the oldest active reader generation are reclaimable.
782 | |||
783 | ||| Example:
784 | |||
785 | ||| Retired <-> [1,2,3,4,5]
786 | ||| Active readers <-> [4,7]
787 | ||| Oldest active reader <-> 4
788 | ||| Safe reclamation <-> [1,2,3]
789 | ||| Result <-> Just 3
790 | |||
791 | ||| Properties:
792 | ||| - O(number of retired snapshots + number of readers).
793 | ||| - Never reclaims a snapshot visible to any active reader.
794 | ||| - Computes a maximal safe reclamation boundary.
795 | |||
796 | export
804 | Nothing
809 | retired
813 | Nothing
817 | --------------------------------------------------------------------------------
818 | -- Reclamation
819 | --------------------------------------------------------------------------------
821 | ||| Reclaims retired snapshots no longer visible to active readers.
822 | |||
823 | ||| Rules:
824 | ||| - No readers: Reclaim everything.
825 | ||| - Readers exist: retain snapshots at or newer than the oldest active reader boundary.
826 | |||
827 | ||| Properties:
828 | ||| - Safe generation-based reclamation.
829 | ||| - Keeps only snapshots potentially observable by readers.
830 | ||| - O(number of retired snapshots + number of readers).
831 | |||
832 | export
836 | mod combinedsnapshotstate (\(MkCombinedSnapshotState snapshot retired readers writepressure rebuildpending batchwindow) =>
841 | []
843 | retired
848 | in MkCombinedSnapshotState snapshot survivors readers writepressure rebuildpending batchwindow
849 | )
851 | --------------------------------------------------------------------------------
852 | -- Single Rebuild Cycle
853 | --------------------------------------------------------------------------------
855 | ||| Executes one rebuild pass.
856 | |||
857 | ||| Steps:
858 | ||| - Rotate all active buffers.
859 | ||| - Collect extracted entries.
860 | ||| - Sort entries deterministically.
861 | ||| - Publish rebuilt snapshot.
862 | ||| - Reclaim retired snapshots.
863 | |||
864 | ||| Returns:
865 | ||| - Newly published generation when entries were processed.
866 | ||| - 0 only when no entries were available and publication did not occur.
867 | ||| - Whether any entries were processed.
868 | |||
869 | ||| Notes:
870 | ||| - Performs exactly one ownership-transfer cycle.
871 | ||| - Does not guarantee complete draining.
872 | |||
880 | -- RotatingBuffers
884 | -- CollectingEntries
894 | -- SortingEntries
899 | -- PublishingSnapshot
910 | --------------------------------------------------------------------------------
911 | -- Flush Until Empty
912 | --------------------------------------------------------------------------------
914 | ||| Repeatedly performs rebuild cycles until a rotation extracts no work.
915 | |||
916 | ||| Behavior:
917 | ||| - Executes rebuild cycles in sequence.
918 | ||| - Each cycle atomically rotates ownership of active buffers.
919 | ||| - Extracted entries are rebuilt into a published snapshot.
920 | ||| - Terminates once a rotation produces no extracted entries.
921 | |||
922 | ||| Visibility guarantees:
923 | ||| - Flush establishes a quiescent visibility boundary at buffer rotation.
924 | ||| - All writes already present in rotated buffers are incorporated before completion.
925 | ||| - Writes arriving concurrently may appear either before or after completion depending on timing.
926 | ||| - Flush does not stop writers or establish a global synchronization barrier.
927 | |||
928 | ||| Concurrency properties:
929 | ||| - Writers continue appending during rebuild execution.
930 | ||| - Multiple rebuild cycles may be required if writes continue arriving.
931 | ||| - Progress remains lock-free for writers.
932 | |||
933 | ||| Returns:
934 | ||| - Final rebuild state.
935 | ||| - Most recently published generation.
936 | |||
937 | ||| Notes:
938 | ||| - Completion means no buffered work was visible during the final rotation.
939 | ||| - This is weaker than "all writes before return".
940 | ||| - Stronger linearizable flush semantics would require an explicit epoch or barrier mechanism.
941 | ||| - Currently unused by rebuild request processing.
942 | ||| - May serve as the implementation basis for future flush semantics.
943 | |||
954 | (st', gen, hadentries) <- rebuildOnce lsmrrbvector.buffers lsmrrbvector.combinedsnapshotstate st
962 | --------------------------------------------------------------------------------
963 | -- Rebuilder Service
964 | --------------------------------------------------------------------------------
966 | ||| Processes a rebuild request issued by the LSM write system.
967 | |||
968 | ||| This service is responsible for advancing the immutable snapshot from the accumulated thread-local mutation buffers.
969 | |||
970 | ||| Two modes of operation exist:
971 | |||
972 | ||| Trigger:
973 | ||| - Performs exactly one rebuildOnce invocation.
974 | ||| - May publish at most one snapshot.
975 | ||| - Additional buffered work remains for future rebuild requests.
976 | |||
977 | ||| Flush:
978 | ||| - Repeatedly performs rebuild cycles until all buffered writes observed at invocation time are incorporated.
979 | ||| - Guarantees that all writes visible in rotated buffers during draining are reflected in the returned generation.
980 | ||| - Concurrent writes may be incorporated either before or after completion.
981 | ||| - May perform multiple rotations and publications internally.
982 | |||
983 | ||| Concurrency guarantees:
984 | ||| - Writers may continue appending during rebuild.
985 | ||| - Flush only guarantees completeness relative to a quiescent cut of buffer rotation visibility.
986 | |||
987 | ||| Return values:
988 | ||| - Trigger returns unit acknowledgement.
989 | ||| - Flush returns the final snapshot generation after draining.
990 | |||
991 | ||| State transitions:
992 | ||| Sleeping → RotatingBuffers → CollectingEntries → SortingEntries → PublishingSnapshot → Sleeping
993 | |||
994 | ||| Notes:
995 | ||| - Empty rebuild cycles do not advance generation.
996 | ||| - Flush drains until a cycle produces no entries.
997 | ||| - Trigger is a bounded operation, Flush is unbounded (but finite under quiescent assumptions).
998 | |||
1013 | --------------------------------------------------------------------------------
1014 | -- Rebuild Service
1015 | --------------------------------------------------------------------------------
1017 | ||| Constructs and launches user-supplied rebuild (writer) actions concurrently.
1018 | |||
1019 | ||| Behavior:
1020 | ||| - Creates a RebuildService endpoint.
1021 | ||| - Routes rebuild requests into handleRebuildRequest.
1022 | ||| - Starts all supplied rebuild-service actions concurrently.
1023 | |||
1024 | ||| Concurrency:
1025 | ||| - Actions execute in parallel.
1026 | ||| - All actions share the same LSMRRBVector instance.
1027 | ||| - All actions share the same rebuild request endpoint.
1028 | |||
1029 | ||| Properties:
1030 | ||| - Service composition utility.
1031 | ||| - Does not itself perform rebuild work.
1032 | ||| - Rebuild execution occurs only when actions issue requests.
1033 | |||
1034 | ||| Notes:
1035 | ||| - Used to launch rebuild workers supporting background maintenance tasks.
1036 | |||
1041 | -> List (LSMRRBVector World a -> RebuildService Poll -> RebuildServiceState -> Async Poll [Errno] ())
1045 | rebuilder
1047 | ignore $
1050 | --------------------------------------------------------------------------------
1051 | -- LSMRRBVector Service
1052 | --------------------------------------------------------------------------------
1054 | ||| Constructs and launches user-supplied reader actions concurrently.
1055 | |||
1056 | ||| Behavior:
1057 | ||| - Executes all supplied actions in parallel.
1058 | ||| - Provides each action access to the shared LSMRRBVector instance.
1059 | |||
1060 | ||| Concurrency:
1061 | ||| - Actions may perform reads.
1062 | ||| - Execution order is not specified.
1063 | ||| - Actions run independently.
1064 | |||
1065 | ||| Properties:
1066 | ||| - Service composition utility.
1067 | ||| - Does not perform vector operations itself.
1068 | |||
1069 | ||| Notes:
1070 | ||| - Used to launch application readers.
1071 | |||
1077 | ignore $
1080 | --------------------------------------------------------------------------------
1081 | -- Rebuild And LSMRRBVector Service
1082 | --------------------------------------------------------------------------------
1084 | ||| Runs rebuild infrastructure and reader workloads together.
1085 | |||
1086 | ||| Behavior:
1087 | ||| - Executes the rebuilderService (writers) and lsmrrbvectorService (readers) concurrently.
1088 | ||| - Allows writers and readers to operate while rebuild work proceeds in the background.
1089 | |||
1090 | ||| Concurrency:
1091 | ||| - Neither service blocks the other.
1092 | ||| - Rebuild publication may occur concurrently with reads and writes.
1093 | |||
1094 | ||| Properties:
1095 | ||| - Top-level composition utility.
1096 | ||| - Establishes the complete LSMRRBVector runtime.
1097 | |||
1098 | ||| Notes:
1099 | ||| - Intended as the final composition point used by runEmptyWith.
1100 | |||
1106 | ignore $
1108 | rebuilderservice
1110 | lsmrrbvectorservice
1111 | ]