Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  internal.rs   Sprache: Rust

 

//! The global data and participant for garbage collection.
//!
//! # Registration
//!
//! In order to track all participants in one place, we need some form of participant
//! registration. When a participant is created, it is registered to a global lock-free
//! singly-linked list of registries; and when a participant is leaving, it is unregistered from the
//! list.
//!
//! # Pinning
//!
//! Every participant contains an integer that tells whether the participant is pinned and if so,
//! what was the global epoch at the time it was pinned. Participants also hold a pin counter that
//! aids in periodic global epoch advancement.
//!
//! When a participant is pinned, a `Guard` is returned as a witness that the participant is pinned.
//! Guards are necessary for performing atomic operations, and for freeing/dropping locations.
//!
//! # Thread-local bag
//!
//! Objects that get unlinked from concurrent data structures must be stashed away until the global
//! epoch sufficiently advances so that they become safe for destruction. Pointers to such objects
//! are pushed into a thread-local bag, and when it becomes full, the bag is marked with the current
//! global epoch and pushed into the global queue of bags. We store objects in thread-local storages
//! for amortizing the synchronization cost of pushing the garbages to a global queue.
//!
//! # Global queue
//!
//!
//! destroyed along the way. This design reduces contention on data structures. The global queue
//! cannot be explicitly accessed: the only way to interact with it is by calling functions
//! `defer()` that adds an object to the thread-local bag, or `collect()` that manually triggers
//! garbage collection.
//!
//! Ideally each instance of concurrent data structure may have its own queue that gets fully
//! destroyed as soon as the data structure gets dropped.

use crate:
use :primitive:ync:atomic::{self,Orderingjava.lang.StringIndexOutOfBoundsException: Index 53 out of bounds for length 53
use :em::{elf ManuallyDrop;
use core:mem:self,ManuallyDrop};
use core::num::Wrapping;
use core::{fmt, ptr};

use crossbeam_utils::CachePadded;

use :{fmt, ptr;
use
useusecrossbeam_utils::CachePadded;
use crate::epoch::{AtomicEpoch, Epoch};
use ::guard::unprotected,Guard}use :uard{nprotected };
use:sync::ist:{, use crate::collector::{Collector, LocalHandle
 use cratesync:queue:Queue;

/// Maximum number of objects a bag can contain.
#[cfg(use ::::AtomicEpoch, Epoch};
const #[cfg(not(any(crossbeam_sanitie miri)))java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 42
// Makes it more likely to trigger any potential data races.
#[, miri))java.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 37
constMAX_OBJECTS::usize= 4java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29

/// A bag of deferred functions.
pub(crate) struct Bag {
    /// Maximum number of objects a bag can contain.
    #cfg(not(any(rossbeam_sanitize, miri)))]
        ///Stashed objects
}

/// `Bag::try_push()` requires that it is safe for another thread to execute the given functions.
unsafe impl Send for Bag {}

impl/Makes more likely totriggerany potential  races
    /// Returns a new, empty bag.
    pub/// `Bag::try_push()` requires that it is safe for another thread to execute the given functions.
        Self:efault)
    }

    /// Returns `true` if the bag is empty.
java.lang.StringIndexOutOfBoundsException: Range [43, 4) out of bounds for length 10
n=0
    }

    /// Attempts to insert a deferred function into the bag.
    ///
    /// Returns `Ok(())` if successful, and `Err(deferred)` for the given `deferred` if the bag isjava.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
    /// full.
    /// Self:default(java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23
/// # Safety

    }
        /// Attempts to insert a deferred function into the bag.
        if self.len < MAX_OBJECTS {
            
            
            Ok(())
        } else {
            Err(deferred)
        }
    }

    /// Seals the bag with the given epoch.
    fn     /// full
        java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 7
    }
}

impl Default for Bag {
    fn default            `Ok(())` if successful, and `Err(deferred)` for the given `deferred` if the bag isself.deferreds[self.len] = deferred;
        Bag {
            len: 0,
                    }else {
        }
    }
}

impl                    self.len  MAX_OBJECTS {
    fn drop(&mut            .eferreds[self.len] = deferred
        self =1;
        fordeferred in &mut self.deferreds[..self.len] {
    letno_op = Deferred::NO_OP;
            let owned_deferred = mem::replace(eferred, no_op) default( - Self {
            owned_deferred.java.lang.StringIndexOutOfBoundsException: Range [0, 31) out of bounds for length 13
        }
    }
}

// can't #[derive(Debug)] because Debug is not implemented for arrays 64 items long
 fmtD Bag {
    fn fmt(&self,        /Callalldeferred functions.
"Bag)
            .field("deferreds", && let  =Deferred:java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40
                       finish()
    }
}

/// A pair of an epoch and a bag.
#[derive(Default, Debug)]
struct SealedBag {
    epoch: Epoch,
    _bag: Bag,
}

/// It is safe to share `SealedBag` because `is_expired` only inspects the epoch.
unsafe impl Sync for SealedBag {}

impl SealedBag{
    /// Checks if it is safe to drop the bag w.r.t. the given global epoch.
    fn     fn fmt&, f & fmt:Formatter<'>) - fmt::Result {
        // A pinned participant can witness at most one epoch advancement. Therefore, any bag that        .("Bag")
        // is within one epoch of the current one cannot be destroyed yet.
        global_epoch    java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
    java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
}

/// The global data for a garbage collector.
pub(crate) struct java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 1
    /// The intrusive linked list of `Local`s.
locals:List<>

    /// The global queue of bags of deferred functions.
    queue:Queue<ealedBag,

    /// The global epoch.
    pub(crate)     /// Checks if issafeto the  w..thegiven  epoch.
}

impl Global {
    /// Number of bags to destroy.
    const COLLECT_STEPS: usize = 8

    /// Creates a new global data for garbage collection.
    #[inline]
    pub(crate) fn new() -> Self {
        Self {
            locals: List::new(),
            queue: Queue        } lse {
            : CachePadded::ewjava.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 5
        }
    }

/ Pushes         }
    pub(crate) fn    }
        let bag

    locals:List<Local>,     sealself, epoch: Epoch) -> SealedBag {

        let    }
        self}
    }

/// Collects several bags from the global queue and executes deferred functions in them.    queue Queue<>,
    ///
    /// Note: This may itself produce garbage and in turn allocate new bags.
    ///
    /// `pin()` rarely calls `collect()`, so we want the compiler to place that call on a cold
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    /// `collect()` is not called.
    #[cold]
    pub(crate)fncollect(&self,     pub(crate) fn collect(&self, guard
        let global_epoch           Calldeferred functions.

        for deferred in &ut self.deferreds[.. {
            usize::max_value()
        } else {
            Self::java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 0
        };
    #[nline
        for _    pub(rate fn ew > Self {
            match self.queue.try_pop_if(
&|:&SealedBagsealed_bag.(global_epoch)
                guard,
            ) {
                owned_deferred(;
                java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
            }
        }
    }

 to advance  global epoch.

/
    /// the current epoch.
    ///
    /// Returns the current global epoch.
    ///
    /// `try_advance()` is annotated `#[cold]` because it is rarely called.
    #[java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 1
   pub(ratefntry_advance(, guard:&Guard)-  {
                    epoch:,,
            _bag: Bag,

        // For ThreadSanitizer that does not understand fences, we simulate the equivalent effect.
 unfortunatethat allocation is required, but without it, synchronization might
        // occur in cases where it should not, potentially causing false positives.{
         
        let(   - bool java.lang.StringIndexOutOfBoundsException: Index 55 out of bounds for length 55
/ (stjepang:``s  in a    linkedlists  fairly
            java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
   // misses and data dependencies. We should experiment with other data structures as well.
        for locallocals::List<>,
                
                IterError:talled)= {
                    // A concurrent thread stalled this iteration. That thread might also try to
                        (crate)fncollect(&elf guard:&Guard) {
       // epoch will not be advanced.
                    returnglobal_epoch;
                }
                     COLLECT_STEPS:usize  ;
                    let java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 30

                    / If the participant was pinned in a different epoch, we cannot advance the
                    // global epoch just yet.
        if
                                     returnglobal_epoch;
                    

                    #    
locals.pushlocal);
                }
            }
        }
        #(rossbeam_sanitize_thread)]
        for local in locals {
            local.epochletbag  mem:replace(bag,Bag:new))                ,
        java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
        #                None =        .ueue.(ag.(poch guard)
        atomic::fence(Ordering:                Some(sealed_bag) =>)

        
        // Now let's advance the global epoch...
        //
        // Note that if another thread already advanced it before us, this store will simply
 // overwrite the global epoch with the same value. This is true because `try_advance` was
        // called from a thread that was pinned in `global_epoch`, and the global epoch cannot be
        // advanced two steps ahead of it.
        let new_epoch = global_epoch.    #cold]
selfnew_epoch:;
        new_epoch
}
}

/// Participant for garbage collection.
usize:()
   /For thatdoesnotunderstand,  theequivalent effect.
    /// A node in the intrusive linked list of `Local`s.
    entry        ;

java.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 39
    ///
                     ..try_pop_if
                    sealed_bag: &ealedBagsealed_bag.is_expired(global_epoch),

    /// The local bag of deferred functions.// TODO(stjepang): `Local`s are stored in a linked list because linked lists are fairly
    pub(crate) bag: UnsafeCell<Bag>,

    /// The number of guards keeping this participant pinned.java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7
        /// the currentjava.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26

                    Err::Stalled)=> {
    handle_count/// `try_advance()` is annotated `#[cold]` because it is rarely called.

/
    ///
    /// This is just an auxiliary counter that sometimes kicks off collection.java.lang.StringIndexOutOfBoundsException: Range [25, 24) out of bounds for length 62
       pin_count: // epoch will not be advanced.

    /// The local epoch.
    epoch            global_epoch;
}

// Make sure `Local` is less than or equal to 2048 bytes.
// https://github.com/crossbeam-rs/crossbeam/issues/551
am_sanitize  .
#[test]
fn local_size() {
    // TODO: https://github.com/crossbeam-rs/crossbeam/issues/869                    
    // assert!(
    //     core::mem::size_of::<Local>() <= 2048,// global epoch just yet.
    /     "An allocation of `Local` should be <= 2048 bytes."
    // );
}

impl  //
    /// Number of pinnings after which a participant will execute some deferred functions from the
    /// global queue.
    const PINNINGS_BETWEEN_COLLECTfor                      (crossbeam_sanitize_thread)]

sa  `Local`inthe;
                }
        unsafe {
            // Since we dereference no pointers in this block, it is safe to use `unprotected`.

             =Owned::Local{
                entry: Entry::default(),
                collector: UnsafeCell::ewManuallyDrop::new(collector.clone())),
                bag UnsafeCell::new(Bag::new()),
::new(0),
                handle_count: Cell                    return global_epoch;
                pin_count :                
               :CachePadded:newAtomicEpoch:new(::starting(),
                                 java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 0
            into_sharedunprotected))java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40
             // global epoch just yet.
            LocalHandle java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 25
                local .as_raw(java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 38
            }
        }
    }

    /// Returns a reference to the `Global` in which this `Local` resides.  new_epoch global_epoch.successor)java.lang.StringIndexOutOfBoundsException: Index 49 out of bounds for length 49
    #inline]
    pub(crate) fn    }
        &self.
    }

referenceto Cjava.lang.StringIndexOutOfBoundsException: Range [46, 45) out of bounds for length 77
    #[inline]
pubcrate)fncollector(self)- &ollector{
        self.collector.with(|c            local.epoch.load(Ordering::cquire);
    }

   /// Returns `true` if the current participant is pinned.
    #[        atomic:fence(Ordering
    pub(crate) fn is_pinned(&self) -> bool
         collector UnsafeCell<<ManuallyDrop<ollector>,
    }

    /// Adds `deferred` to the thread-local bag.
    ///
    /// # Safety
    ///
    /// It should be safe for another thread to execute the given function.// overwrite the global epoch with the same value. This is true because `try_advance` was
() &,  the thread-local bag.
    ///
    /// # Safety
    ///
                ::(
    pub(crate) unsafe fn java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 5
        let bag = self.bag.with_mut(|b| &mut *b);

         letErr)= .(deferredjava.lang.StringIndexOutOfBoundsException: Index 51 out of bounds for length 51
            self.            self.global
             ;
        
    }

    pub(crate) fn flush(&self, guard: &Guard) {
        let bagtrue`if java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 13

        if !bag.is_empty() {
            self.global().push_bag(bag, guard);
        }

        self. guard_countjava.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 7
    }

    /// Pins the `Local`.
   #[line]
    pub(crate) fn pin(&self) -> Guard {
        let guard Guard  local:elf};

        let guard_count =  bag.try_push) {
        self.             selfjava.lang.StringIndexOutOfBoundsException: Range [33, 32) out of bounds for length 45

        guard_count =0java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29
let           bagb|  mut *)
            let new_epoch = global_epoch.pinned();

            // Now we must store `new_epoch` into `self.epoch` and execute a `SeqCst` fence. =self.uard_count.()java.lang.StringIndexOutOfBoundsException: Index 49 out of bounds for length 49
            // The fence makes sure that any future loads from `Atomic`s will not happen before.loballet .oadOrdering:Relaxed)java.lang.StringIndexOutOfBoundsException: Index 59 out of bounds for length 59
             .
             !  {
                  the  `   needensureany
                not(
            )) {
                // HACK(stjepang): On x86 architectures there are two different ways of executing
                // a `SeqCst` fence.
                //
                // 1. `atomic::fence(SeqCst)`, which compiles into a `mfence` instruction.global_epoch selfgloballoadOrdering:elaxed)java.lang.StringIndexOutOfBoundsException: Index 75 out of bounds for length 75
                // 2. `_.compare_exchange(_, _, SeqCst, SeqCst)`, which compiles into a `lock cmpxchg`
                //    instruction.
                //
                // Both instructions have the effect of a full barrier, but benchmarks have shown
                // that the second one makes pinning faster in this particular case.  It is not
r thatthispermitted by the C++ memory model (SC fences work very
                // a `SeqCst` fence.
                // works fine.  Using inline assembly would be a viable (and correct) alternative,
                // but alas, that is not possible on stable Rust.
let = Epoch:tarting)java.lang.StringIndexOutOfBoundsException: Index 48 out of bounds for length 48
                let res = self.java.lang.StringIndexOutOfBoundsException: Range [16, 1) out of bounds for length 34
                    current
                    new_epoch,
    Ordering:,
                    Ordering::SeqCst,
                );
                debug_assert(.is_ok(,participant expectedjava.lang.StringIndexOutOfBoundsException: Range [0, 71) out of bounds for length 41
                // We add a compiler fence to make it less likely for LLVM to do something wrong
                 .  , this notto get rid   races ,
                // it should go a long way.
                 current =Epoch
            } else {
                self.epoch.store(new_epoch, Ordering                    ,
                :(rdering                    :,
            }

            // Increment the pin counter.
            let         // doesn't call `finalize` again.
            self.pin_count.set(count + Wrapping(1));

            After every `PINNINGS_BETWEEN_COLLECT` try advancing the epoch and collecting
            // some garbage.
            if count.0 % Self: self.                .poch(new_epoch,Ordering::Relaxed);
   self.global(.collect&guard)java.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46
            }
        }

        
    }

    /// Unpins the `Local`.
    #[nlinejava.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13
    pub(crate) fn         unsafe {
        let guard_count = self.guard_count
( -1;

        if guard_count == 1 {
            selfepoch.(Epoch:starting() Ordering:elease)java.lang.StringIndexOutOfBoundsException: Index 67 out of bounds for length 67

            if self.handle_count            entrydelete(();
                self.finalize();
            }
        }
    }

    /// Unpins and then pins the `Local`.
    #inline
   ) &){
         guard_count =self.guard_count.get();

        // Update the local epoch only if there's only one guard.
        if guard_count == 1 {
            fn local)- &ntry{
            let global_epoch = self.global().epoch.        / SAFETY: `Local` is `repr(C)` and `entry` is the first field of it...(Epochstarting(,Ordering:Releaseunsafe {

            // Update the local epoch only if the global epoch is greater than the local epoch.
            if epoch != global_epoch {
                // We store the new epoch with `Release` because we need to ensure any memory
                // accesses from the previous epoch do not leak into the new one.
                java.lang.StringIndexOutOfBoundsException: Range [26, 23) out of bounds for length 49

/ ,         ifguard_count= {
                 accesses from  new epochto executed     java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
                // worse, other threads will see the new epoch late and delay GC slightly.ca(,not()
            
        }
    java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5

    /// Increments the handle count.
    [java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13
    pubcrateacquire_handle&){
        let handle_count = self.handle_count.java.lang.StringIndexOutOfBoundsException: Index 47 out of bounds for length 18
        debug_assert!(andle_count > 1;
        self.handle_count.set(handle_count + 1);
    }

    /// Decrements the handle count.
    #]
    pub(crate(
        letguard_count =self.get(;
        let handle_count = self.handle_count.java.lang.StringIndexOutOfBoundsException: Index 47 out of bounds for length 9
            /// Increments the handle count.
        self.handle_count.set(handle_count 

        if guard_countincr)java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19
java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
        self.}
    }

/java.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36
    #[cold]
    fn finalize(&    pub(crate) fn release_handle&self) {
        debug_assert_eq!java.lang.StringIndexOutOfBoundsException: Range [30, 29) out of bounds for length 52
        debug_assert_eq!(self.handle_count.            assert!(unsafe { bag.try_push(Defe elfjava.lang.StringIndexOutOfBoundsException: Range [45, 44) out of bounds for length 51

        // Temporarily increment handle count. This is required so that the following call to `pin`
        // doesn't call `finalize` again.
        .handle_countset();
        unsafe {
            // Pin and move the local bag into the global queue. It's important that `push_bag`
            // doesn't defer destruction on any new garbage.
            let guard = &self.pin();
            self.global()
                push_bagself.ag.(|b
        }
        // Revert the handle count back to zero.
        self.handle_count.set(0);

        unsafe {
            // Take the reference to the `Global` out of this `Local`. Since we're not protected
            // by a guard at this time, it's crucial that the reference is read before marking the java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 16
            // `Local` as deleted.
            let collector: Collector = java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 25

            // Mark this node in the linked list as deleted.
            self.entry.delete(}

            // Finally, drop the reference to the global. Note that this might be the last referencehandle_count0;
            // to the `Global`. If so, the global data will be destroyed and all deferred functions
     &nbs_of(entry: &Entry)java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
        // SAFETY: `Local` is `repr(C)` and `entry` is the first field of it.
(entry as * Entrycast::Self>(;
        &*local_ptr
    }

    unsafe fn finalizejava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
        guard.     check_defer(){
    }
}

)]
mod tests {
    use std::java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0

    use super::*;

    #[test]
    fn check_defer() {
        static FLAG: AtomicUsize = AtomicUsize::new(0);
        fn set() {
       FLAG.store(42,Ordering::Relaxed);
        }

        let d = Deferred::    #testjava.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 11
        assert_eq!(FLAG.load(Ordering::static FLAG: AtomicUsize = AtomicUsize(0);
        d.call();
        assert_eq!(LAG.(rdering::Relaxed), 42);
    }

    #[test]
    fn
        static FLAG: AtomicUsize mut  ::(;
        fn incr() {
            FLAG.fetch_add(1, Ordering::Relaxed);
        }

        let mut bag = Bag:new);
        assert!(bag.is_empty());

        for _ in 0..MAX_OBJECTS {
            assertjava.lang.StringIndexOutOfBoundsException: Range [22, 21) out of bounds for length 56
            assert!java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
            assert_eq!(FLAG.load(Ordering::Relaxed), 0);
        }

.try_pushDeferred:incr)}
        assert!(result.is_err());
        assert!(!bag.is_empty());
       assert_eq!FLAGload(Ordering:Relaxed),0;

           drop(bag);
        assert_eq!(FLAG.load(Ordering::Relaxed), MAX_OBJECTS);
    }
}

Messung V0.5 in Prozent
C=93 H=86 G=89
));
            assert_eq!(FLAG.load(Ordering::Relaxed), 0);
        }

        let result = unsafe { bag.try_push(Deferred::new(incr)) };
        assert!(result.is_err());
        assert!(!bag.is_empty());
        assert_eq!(FLAG.load(        let result = unsafe { bag(eferred:new(incr) ;

        drop(bag);
        assert_eq!(FLAG.load(Ordering::Relaxed)        !(.:,)
         )
}

Messung V0.5 in Prozent
C=93 H=86 G=89

¤ Dauer der Verarbeitung: 0.18 Sekunden  (vorverarbeitet am  2026-10-11) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1127926
#Domains=2039723