Beispiel #1
0
        // Must be called from within the ThreadSafety
        private void StatusChangedCallback(C4ReplicatorStatus status)
        {
            if (_disposed)
            {
                return;
            }

            if (status.level == C4ReplicatorActivityLevel.Stopped)
            {
                if (HandleError(status.error))
                {
                    status.level = C4ReplicatorActivityLevel.Offline;
                }
            }
            else if (status.level > C4ReplicatorActivityLevel.Connecting)
            {
                _retryCount = 0;
                _reachability?.Stop();
                _reachability = null;
            }

            UpdateStateProperties(status);
            if (status.level == C4ReplicatorActivityLevel.Stopped)
            {
                ClearRepl();
                Config.Database.ActiveReplications.Remove(this);
            }

            try {
                _statusChanged.Fire(this, new ReplicatorStatusChangedEventArgs(Status));
            } catch (Exception e) {
                Log.To.Sync.W(Tag, "Exception during StatusChanged callback", e);
            }
        }
Beispiel #2
0
        private static void StatusChangedCallback(C4Replicator *repl, C4ReplicatorStatus status, void *context)
        {
            var replicator = GCHandle.FromIntPtr((IntPtr)context).Target as Replicator;

            replicator?.DispatchQueue.DispatchSync(() =>
            {
                replicator.StatusChangedCallback(status);
            });
        }
        private static void StatusChangedCallback(C4ReplicatorStatus status, object context)
        {
            var repl = context as Replicator;

            repl?._threadSafetyQueue.DispatchSync(() =>
            {
                repl.StatusChangedCallback(status);
            });
        }
Beispiel #4
0
        private static void StatusChangedCallback(C4Replicator *repl, C4ReplicatorStatus status, void *context)
        {
            var replicator = GCHandle.FromIntPtr((IntPtr)context).Target as Replicator;

            if (replicator == null)
            {
                return;
            }

            replicator.WaitPendingConflictTasks(status);
            replicator.DispatchQueue.DispatchSync(() =>
            {
                replicator.StatusChangedCallback(status);
            });
        }
Beispiel #5
0
        private void UpdateStateProperties(C4ReplicatorStatus state)
        {
            Exception error = null;

            if (state.error.code > 0)
            {
                error = CouchbaseException.Create(state.error);
            }

            _rawStatus = state;
            var level    = (ReplicatorActivityLevel)state.level;
            var progress = new ReplicatorProgress(state.progress.unitsCompleted, state.progress.unitsTotal);

            Status = new ReplicatorStatus(level, progress, error);
            WriteLog.To.Sync.I(Tag, $"{this} is {state.level}, progress {state.progress.unitsCompleted}/{state.progress.unitsTotal}");
        }
Beispiel #6
0
        private void WaitPendingConflictTasks(C4ReplicatorStatus status)
        {
            if (status.error.code == 0 && status.error.domain == 0)
            {
                return;
            }

            if (status.level == C4ReplicatorActivityLevel.Stopped ||
                status.level == C4ReplicatorActivityLevel.Idle)
            {
                var array = _conflictTasks?.Keys?.ToArray();
                if (array != null)
                {
                    Task.WaitAll(array);
                }
            }
        }
Beispiel #7
0
        /// <summary>
        /// Starts the replication with an option to reset the checkpoint.
        /// </summary>
        /// <param name="reset">Resets the local checkpoint of the replicator, meaning that it will read all changes since the beginning
        /// of time from the remote database.
        /// </param>
        public void Start(bool reset)
        {
            var status = default(C4ReplicatorStatus);

            DispatchQueue.DispatchSync(() =>
            {
                if (_disposed)
                {
                    throw new ObjectDisposedException(CouchbaseLiteErrorMessage.ReplicatorDisposed);
                }

                var err = SetupC4Replicator();
                if (err.code > 0)
                {
                    WriteLog.To.Sync.E(Tag, $"Setup replicator {this} failed.");
                }

                if (_repl != null)
                {
                    status = Native.c4repl_getStatus(_repl);
                    if (status.level == C4ReplicatorActivityLevel.Stopped ||
                        status.level == C4ReplicatorActivityLevel.Stopping ||
                        status.level == C4ReplicatorActivityLevel.Offline)
                    {
                        ServerCertificate = null;
                        WriteLog.To.Sync.I(Tag, $"{this}: Starting");
                        Native.c4repl_start(_repl, Config.Options.Reset || reset);
                        Config.Options.Reset = false;
                        Config.Database.AddActiveStoppable(this);
                        status = Native.c4repl_getStatus(_repl);
                    }
                }
                else
                {
                    status = new C4ReplicatorStatus {
                        error    = err,
                        level    = C4ReplicatorActivityLevel.Stopped,
                        progress = new C4Progress()
                    };
                }
            });

            UpdateStateProperties(status);
            DispatchQueue.DispatchSync(() => StatusChangedCallback(status));
        }
Beispiel #8
0
        private void WaitPendingConflictTasks(C4ReplicatorStatus status)
        {
            if (status.error.code == 0 && status.error.domain == 0)
            {
                return;
            }

            bool transient;

            if (!IsPermanentError(status.error, out transient))
            {
                return;
            }

            if (status.level == C4ReplicatorActivityLevel.Stopped)
            {
                var array = _conflictTasks?.Keys?.ToArray();
                if (array != null)
                {
                    Task.WaitAll(array);
                }
            }
        }
Beispiel #9
0
        // Must be called from within the ThreadSafety
        private void StatusChangedCallback(C4ReplicatorStatus status)
        {
            if (_disposed)
            {
                return;
            }

            // idle or busy
            if ((status.level > C4ReplicatorActivityLevel.Connecting &&
                 status.level != C4ReplicatorActivityLevel.Stopping) &&
                status.error.code == 0)
            {
                StopReachabilityObserver();
            }

            UpdateStateProperties(status);

            // offline
            if (status.level == C4ReplicatorActivityLevel.Offline)
            {
                StartReachabilityObserver();
            }

            //  stopped
            if (status.level == C4ReplicatorActivityLevel.Stopped)
            {
                StopReachabilityObserver();
                Stopped();
            }

            try {
                _statusChanged.Fire(this, new ReplicatorStatusChangedEventArgs(Status));
            } catch (Exception e) {
                WriteLog.To.Sync.W(Tag, "Exception during StatusChanged callback", e);
            }
        }
Beispiel #10
0
        // Must be called from within the ThreadSafety
        private void StartInternal()
        {
            _desc = ToString(); // Cache this; it may be called a lot when logging

            // Target:
            var      addr      = new C4Address();
            var      scheme    = new C4String();
            var      host      = new C4String();
            var      path      = new C4String();
            Database otherDB   = null;
            var      remoteUrl = Config.RemoteUrl;
            string   dbNameStr = null;

            if (remoteUrl != null)
            {
                var pathStr = String.Concat(remoteUrl.Segments.Take(remoteUrl.Segments.Length - 1));
                dbNameStr     = remoteUrl.Segments.Last().TrimEnd('/');
                scheme        = new C4String(remoteUrl.Scheme);
                host          = new C4String(remoteUrl.Host);
                path          = new C4String(pathStr);
                addr.scheme   = scheme.AsC4Slice();
                addr.hostname = host.AsC4Slice();
                addr.port     = (ushort)remoteUrl.Port;
                addr.path     = path.AsC4Slice();
            }
            else
            {
                otherDB = Config.OtherDB;
            }

            var options  = Config.Options;
            var userInfo = remoteUrl?.UserInfo?.Split(':');

            if (userInfo?.Length == 2)
            {
                throw new ArgumentException(
                          "Embedded credentials in a URL (username:password@url) are not allowed; use the BasicAuthenticator class instead");
            }

            Config.Authenticator?.Authenticate(options);

            options.Build();
            var push       = Config.ReplicatorType.HasFlag(ReplicatorType.Push);
            var pull       = Config.ReplicatorType.HasFlag(ReplicatorType.Pull);
            var continuous = Config.Continuous;

            // Clear the reset flag, it is a one-time thing
            Config.Options.Reset = false;

            var socketFactory = Config.SocketFactory;

            socketFactory.context = GCHandle.ToIntPtr(GCHandle.Alloc(this)).ToPointer();
            _nativeParams         = new ReplicatorParameters(options)
            {
                Push            = Mkmode(push, continuous),
                Pull            = Mkmode(pull, continuous),
                Context         = this,
                OnDocumentError = OnDocError,
                OnStatusChanged = StatusChangedCallback,
                SocketFactory   = &socketFactory
            };

            var err    = new C4Error();
            var status = default(C4ReplicatorStatus);

            _stopping = false;
            _databaseThreadSafety.DoLocked(() =>
            {
                C4Error localErr;
                _repl = Native.c4repl_new(Config.Database.c4db, addr, dbNameStr, otherDB != null ? otherDB.c4db : null,
                                          _nativeParams.C4Params, &localErr);
                err = localErr;
                if (_repl != null)
                {
                    status = Native.c4repl_getStatus(_repl);
                    Config.Database.ActiveReplications.Add(this);
                }
                else
                {
                    status = new C4ReplicatorStatus {
                        error    = err,
                        level    = C4ReplicatorActivityLevel.Stopped,
                        progress = new C4Progress()
                    };
                }
            });

            scheme.Dispose();
            path.Dispose();
            host.Dispose();

            UpdateStateProperties(status);
            DispatchQueue.DispatchSync(() => StatusChangedCallback(status));
        }