|
127 | 127 | [^ByteBuffer buf]
|
128 | 128 | (when (.isDirect buf)
|
129 | 129 | (try
|
130 |
| - |
| 130 | + |
131 | 131 | (let [^Method clean @clean
|
132 | 132 | cleaner (doto (.getMethod (class buf) "cleaner" nil)
|
133 | 133 | (.setAccessible true))]
|
|
203 | 203 | ;; [ exists? : int8
|
204 | 204 | ;; state : int8
|
205 | 205 | ;; checksum : int64
|
206 |
| -;; size : int32 |
| 206 | +;; size : int32 |
207 | 207 | ;; payload : array ]
|
208 | 208 | ;; valid values for 'exists' is 0 (no), 1 (yes)
|
209 | 209 | ;; valid values for 'state' is 0 (unclaimed), 1 (in progress), 2 (complete)
|
|
216 | 216 | (let [^ByteBuffer
|
217 | 217 | buf' (-> (buffer slab)
|
218 | 218 | (.position pos))]
|
219 |
| - |
| 219 | + |
220 | 220 | ;; is there a next task, and is there space left in the buffer?
|
221 | 221 | (when (and
|
222 | 222 | (pos? (.remaining buf'))
|
223 | 223 | (== 1 (.get buf')))
|
224 |
| - |
| 224 | + |
225 | 225 | (lazy-seq
|
226 | 226 | (let [status (.get buf')
|
227 | 227 | checksum (.getLong buf')
|
228 | 228 | size (.getInt buf')]
|
229 | 229 | (cons
|
230 |
| - |
| 230 | + |
231 | 231 | (task
|
232 | 232 | slab
|
233 | 233 | pos
|
234 | 234 | (+ header-size size)
|
235 | 235 | (read-write-lock slab))
|
236 |
| - |
| 236 | + |
237 | 237 | (slab->task-seq
|
238 | 238 | slab
|
239 | 239 | (+ pos header-size size)))))))
|
|
266 | 266 |
|
267 | 267 | (mapped? [_]
|
268 | 268 | (boolean @buf))
|
269 |
| - |
| 269 | + |
270 | 270 | (unmap [_]
|
271 | 271 | (with-exclusive-lock lock
|
272 | 272 | (when (.exists (io/file filename))
|
|
308 | 308 | (.putInt cnt)
|
309 | 309 | (.put ary)
|
310 | 310 | (.put (byte 0))) ;; next doesn't exist
|
311 |
| - |
| 311 | + |
312 | 312 | (swap! position + header-size cnt)
|
313 | 313 |
|
314 | 314 | (invalidate this pos (+ header-size cnt))
|
315 |
| - |
| 315 | + |
316 | 316 | ;; return a task to enqueue in-memory
|
317 | 317 | (task
|
318 | 318 | this
|
319 | 319 | pos
|
320 | 320 | (+ header-size cnt)
|
321 | 321 | lock)))))
|
322 |
| - |
| 322 | + |
323 | 323 | clojure.lang.Seqable
|
324 | 324 | (seq [this]
|
325 | 325 | (slab->task-seq this))
|
|
357 | 357 |
|
358 | 358 | (when-not (.createNewFile f)
|
359 | 359 | (throw (IOException. (str "Could not create new slab file at " (.getAbsolutePath f)))))
|
360 |
| - |
| 360 | + |
361 | 361 | (TaskSlab.
|
362 | 362 | (.getAbsolutePath f)
|
363 | 363 | q-name
|
|
413 | 413 | (defn- immediate-stats [^LinkedBlockingQueue q {:keys [enqueued retried completed]}]
|
414 | 414 | (let [cnt (.size q)
|
415 | 415 | completed (.get ^AtomicLong completed)
|
416 |
| - enqueued (.get ^AtomicLong enqueued)] |
417 |
| - {:enqueued enqueued |
| 416 | + enqueued (.get ^AtomicLong enqueued)] |
| 417 | + {:enqueued enqueued |
418 | 418 | :retried (.get ^AtomicLong retried)
|
419 | 419 | :completed completed
|
420 | 420 | :in-progress (- (- enqueued completed) cnt)}))
|
|
478 | 478 | (or fsync-threshold fsync-interval)
|
479 | 479 | (or fsync-take? fsync-put?)))
|
480 | 480 | "Both batch and per-task fsync options are enabled, which is probably not what you intended.")
|
481 |
| - |
| 481 | + |
482 | 482 | (.mkdirs (io/file directory))
|
483 | 483 |
|
484 | 484 | (let [
|
485 |
| - |
| 485 | + |
486 | 486 | queue (memoize (fn [_] (LinkedBlockingQueue. (int max-queue-size))))
|
487 | 487 | queue-name->files (directory->queue-name->slab-files directory)
|
488 | 488 |
|
|
505 | 505 |
|
506 | 506 | queue-name->current-slab (atom {})
|
507 | 507 |
|
508 |
| - ;; initialize |
| 508 | + ;; initialize |
509 | 509 | slabs (->> @queue-name->slabs vals (apply concat))
|
510 | 510 | slab->count (zipmap
|
511 | 511 | slabs
|
|
539 | 539 | this-ref (promise)
|
540 | 540 |
|
541 | 541 | action-counter (AtomicLong. 0)
|
542 |
| - |
| 542 | + |
543 | 543 | mark-action! (if fsync-threshold
|
544 | 544 | (fn []
|
545 | 545 | (when (zero? (rem (.incrementAndGet action-counter) fsync-threshold))
|
546 | 546 | (fsync @this-ref)))
|
547 | 547 | (fn []))]
|
548 | 548 |
|
549 |
| - ;; |
| 549 | + ;; |
550 | 550 | (when fsync-interval
|
551 | 551 | (future
|
552 | 552 | (let [ref (WeakReference. @this-ref)]
|
553 | 553 | (while (.get ref)
|
554 | 554 | (when-let [q (.get ref)]
|
555 | 555 | (try
|
556 |
| - (Thread/sleep fsync-interval) |
557 |
| - (fsync q) |
| 556 | + (let [start (System/currentTimeMillis)] |
| 557 | + (fsync q) |
| 558 | + (let [end (System/currentTimeMillis)] |
| 559 | + (Thread/sleep (max 0 (- fsync-interval (- end start)))))) |
558 | 560 | (catch Throwable e
|
559 | 561 | )))))))
|
560 |
| - |
| 562 | + |
561 | 563 | ;; populate queues with pre-existing tasks
|
562 | 564 | (let [empty-slabs (atom #{})]
|
563 | 565 | (doseq [[q slabs] @queue-name->slabs]
|
|
571 | 573 | ::fsync? fsync-take?))
|
572 | 574 | (remove #(or (= :complete (status %))
|
573 | 575 | (and complete? (complete? @%)))))]
|
574 |
| - |
| 576 | + |
575 | 577 | (if (empty? tasks)
|
576 |
| - |
| 578 | + |
577 | 579 | ;; if there aren't any active tasks, just delete the slab
|
578 | 580 | (do
|
579 | 581 | (delete-slab slab)
|
580 | 582 | (swap! empty-slabs conj slab))
|
581 |
| - |
| 583 | + |
582 | 584 | (do
|
583 | 585 | (doseq [task tasks]
|
584 | 586 | (status! task :incomplete)
|
|
612 | 614 | (fsync [_]
|
613 | 615 | (doseq [slab (->> @queue-name->slabs vals (apply concat))]
|
614 | 616 | (sync! slab)))
|
615 |
| - |
| 617 | + |
616 | 618 | (mark-retry! [_ q-name]
|
617 | 619 | (mark-action!)
|
618 | 620 | (populate-stats! q-name)
|
619 | 621 | (let [^AtomicLong retry-counter (get-in @queue-name->stats [q-name :retried])]
|
620 | 622 | (.incrementAndGet retry-counter)))
|
621 |
| - |
| 623 | + |
622 | 624 | (mark-complete! [_ q-name]
|
623 | 625 | (mark-action!)
|
624 | 626 | (populate-stats! q-name)
|
625 | 627 | (let [^AtomicLong retry-counter (get-in @queue-name->stats [q-name :completed])]
|
626 | 628 | (.incrementAndGet retry-counter)))
|
627 |
| - |
| 629 | + |
628 | 630 | (stats [_]
|
629 | 631 | (let [ks (keys @queue-name->stats)]
|
630 | 632 | (zipmap ks
|
|
657 | 659 | butlast
|
658 | 660 | (remove #(= slab %)))]
|
659 | 661 | (unmap s))))
|
660 |
| - |
| 662 | + |
661 | 663 | (status! t :in-progress)
|
662 | 664 | ;; we don't need to fsync here, because in-progress and incomplete
|
663 | 665 | ;; are effectively equivalent on restart
|
|
666 | 668 | timeout-val)
|
667 | 669 | (catch TimeoutException _
|
668 | 670 | timeout-val))))
|
669 |
| - |
| 671 | + |
670 | 672 | (take! [this q-name]
|
671 | 673 | (take! this q-name Long/MAX_VALUE nil))
|
672 | 674 |
|
|
690 | 692 | (throw
|
691 | 693 | (IllegalArgumentException.
|
692 | 694 | (str "Can't enqueue task whose serialized representation is larger than :slab-size, which is currently " slab-size))))
|
693 |
| - |
| 695 | + |
694 | 696 | (when fsync-put?
|
695 | 697 | (sync! slab))
|
696 | 698 | task))
|
697 |
| - |
| 699 | + |
698 | 700 | queue! (fn [task]
|
699 | 701 | (if (zero? timeout)
|
700 | 702 | (.offer q task)
|
|
714 | 716 | false)
|
715 | 717 |
|
716 | 718 | nil))
|
717 |
| - |
| 719 | + |
718 | 720 | (put! [this q-name task-descriptor]
|
719 | 721 | (put! this q-name task-descriptor Long/MAX_VALUE))))
|
720 | 722 |
|
|
0 commit comments