public SynchronizationThread(NoteRepository repository, ISynchronizationFeedback[] synclistener, ConflictResolutionStrategyConfig strat, IAlephDispatcher disp) { repo = repository; listener = synclistener.ToList(); conflictStrategy = ConflictResolutionStrategyHelper.ToInterfaceType(strat); dispatcher = disp; _comChannel = new ManualResetEvent(false); }
public void OpenWithAutomaticConflictResolution(string filename, DataSource source, ConflictResolutionStrategy resolutionStrategy, Action <SavedGameRequestStatus, ISavedGameMetadata> completedCallback) { Misc.CheckNotNull(filename); Misc.CheckNotNull(completedCallback); var prefetchDataOnConflict = false; ConflictCallback conflictCallback = null; completedCallback = ToOnGameThread(completedCallback); if (conflictCallback == null) { conflictCallback = (resolver, original, originalData, unmerged, unmergedData) => { switch (resolutionStrategy) { case ConflictResolutionStrategy.UseOriginal: resolver.ChooseMetadata(original); return; case ConflictResolutionStrategy.UseUnmerged: resolver.ChooseMetadata(unmerged); return; case ConflictResolutionStrategy.UseLongestPlaytime: if (original.TotalTimePlayed >= unmerged.TotalTimePlayed) { resolver.ChooseMetadata(original); } else { resolver.ChooseMetadata(unmerged); } return; default: Logger.e("Unhandled strategy " + resolutionStrategy); completedCallback(SavedGameRequestStatus.InternalError, null); return; } } } ; conflictCallback = ToOnGameThread(conflictCallback); if (!IsValidFilename(filename)) { Logger.e("Received invalid filename: " + filename); completedCallback(SavedGameRequestStatus.BadInputError, null); return; } InternalOpen(filename, source, resolutionStrategy, prefetchDataOnConflict, conflictCallback, completedCallback); }
public HttpResponseMessage ResolveConflict(string filename, ConflictResolutionStrategy strategy) { var canonicalFilename = FileHeader.Canonize(filename); if (Log.IsDebugEnabled) { Log.Debug("Resolving conflict of a file '{0}' by using {1} strategy", filename, strategy); } switch (strategy) { case ConflictResolutionStrategy.CurrentVersion: Storage.Batch(accessor => { var localMetadata = accessor.GetFile(canonicalFilename, 0, 0).Metadata; var conflict = accessor.GetConfigurationValue <ConflictItem>(RavenFileNameHelper.ConflictConfigNameForFile(canonicalFilename)); ConflictResolver.ApplyCurrentStrategy(canonicalFilename, conflict, localMetadata); accessor.UpdateFileMetadata(canonicalFilename, localMetadata, null); ConflictArtifactManager.Delete(canonicalFilename, accessor); }); Publisher.Publish(new ConflictNotification { FileName = canonicalFilename, Status = ConflictStatus.Resolved }); break; case ConflictResolutionStrategy.RemoteVersion: Storage.Batch(accessor => { var localMetadata = accessor.GetFile(canonicalFilename, 0, 0).Metadata; var conflict = accessor.GetConfig(RavenFileNameHelper.ConflictConfigNameForFile(canonicalFilename)).JsonDeserialization <ConflictItem>(); ConflictResolver.ApplyRemoteStrategy(canonicalFilename, conflict, localMetadata); accessor.UpdateFileMetadata(canonicalFilename, localMetadata, null); accessor.SetConfig(RavenFileNameHelper.ConflictConfigNameForFile(canonicalFilename), JsonExtensions.ToJObject(conflict)); // ConflictArtifactManager.Delete(canonicalFilename, accessor); - intentionally not deleting, conflict item will be removed when a remote file is put }); SynchronizationTask.Context.NotifyAboutWork(); break; default: throw new NotSupportedException(string.Format("{0} is not the valid strategy to resolve a conflict", strategy)); } return(GetEmptyMessage(HttpStatusCode.NoContent)); }
/// <summary> /// Avoids the additional database trip that using SqliteCommandBuilder requires. /// </summary> /// <returns>The insert command.</returns> /// <param name="table">Table.</param> /// <param name="values">Values.</param> /// <param name="conflictResolutionStrategy">Conflict resolution strategy.</param> sqlite3_stmt GetInsertCommand(String table, ContentValues values, ConflictResolutionStrategy conflictResolutionStrategy) { if (!IsOpen) { Open(Path); } var builder = new StringBuilder("INSERT"); if (conflictResolutionStrategy != ConflictResolutionStrategy.None) { builder.Append(" OR "); builder.Append(conflictResolutionStrategy); } builder.Append(" INTO "); builder.Append(table); builder.Append(" ("); // Append our content column names and create our SQL parameters. var valueSet = values.ValueSet(); var valueBuilder = new StringBuilder(); var index = 0; var args = new object[valueSet.Count]; foreach (var column in valueSet) { if (index > 0) { builder.Append(","); valueBuilder.Append(","); } builder.AppendFormat("{0}", column.Key); valueBuilder.Append("?"); args[index] = column.Value; index++; } builder.Append(") VALUES ("); builder.Append(valueBuilder); builder.Append(")"); var sql = builder.ToString(); sqlite3_stmt command; lock (dbLock) { command = db.prepare(sql); command.bind(args); } return(command); }
public override bool TryResolve(string fileName, RavenJObject localMedatada, RavenJObject remoteMetadata, out ConflictResolutionStrategy resolutionStrategy) { var remoteFileLastModified = GetLastModified(remoteMetadata); var localFileLastModified = GetLastModified(localMedatada); if (remoteFileLastModified > localFileLastModified) resolutionStrategy = ConflictResolutionStrategy.RemoteVersion; else resolutionStrategy = ConflictResolutionStrategy.CurrentVersion; return true; }
public void OpenWithAutomaticConflictResolution(string filename, DataSource source, ConflictResolutionStrategy resolutionStrategy, Action <SavedGameRequestStatus, ISavedGameMetadata> callback) { bubble.CheckNotNull(filename); bubble.CheckNotNull(callback); callback = ToOnGameThread(callback); if (!IsValidFilename(filename)) { Logger.e("Received invalid filename: " + filename); callback(SavedGameRequestStatus.BadInputError, null); return; } OpenWithManualConflictResolution( filename, source, false, (resolver, original, originalData, unmerged, unmergedData) => { switch (resolutionStrategy) { case ConflictResolutionStrategy.UseOriginal: resolver.ChooseMetadata(original); return; case ConflictResolutionStrategy.UseUnmerged: resolver.ChooseMetadata(unmerged); return; case ConflictResolutionStrategy.UseLongestPlaytime: if (original.TotalTimePlayed >= unmerged.TotalTimePlayed) { resolver.ChooseMetadata(original); } else { resolver.ChooseMetadata(unmerged); } return; default: Logger.e("Unhandled strategy " + resolutionStrategy); callback(SavedGameRequestStatus.InternalError, null); return; } }, callback ); }
public HttpResponseMessage ResolveConflict(string fileName, ConflictResolutionStrategy strategy) { Log.Debug("Resolving conflict of a file '{0}' by using {1} strategy", fileName, strategy); if (strategy == ConflictResolutionStrategy.CurrentVersion) { StrategyAsGetCurrent(fileName); } else { StrategyAsGetRemote(fileName); } return(GetEmptyMessage(HttpStatusCode.NoContent)); }
private static Types.SnapshotConflictPolicy AsConflictPolicy(ConflictResolutionStrategy strategy) { switch (strategy) { case ConflictResolutionStrategy.UseLongestPlaytime: return(Types.SnapshotConflictPolicy.LONGEST_PLAYTIME); case ConflictResolutionStrategy.UseOriginal: return(Types.SnapshotConflictPolicy.LAST_KNOWN_GOOD); case ConflictResolutionStrategy.UseUnmerged: return(Types.SnapshotConflictPolicy.MOST_RECENTLY_MODIFIED); } throw new InvalidOperationException("Found unhandled strategy: " + strategy); }
/// <summary> /// Avoids the additional database trip that using SqliteCommandBuilder requires. /// </summary> /// <returns>The insert command.</returns> /// <param name="table">Table.</param> /// <param name="values">Values.</param> /// <param name="conflictResolutionStrategy">Conflict resolution strategy.</param> ISQLiteStatement GetInsertCommand(String table, ContentValues values, ConflictResolutionStrategy conflictResolutionStrategy) { var builder = new StringBuilder("INSERT"); if (conflictResolutionStrategy != ConflictResolutionStrategy.None) { builder.Append(" OR "); builder.Append(conflictResolutionStrategy); } builder.Append(" INTO "); builder.Append(table); builder.Append(" ("); // Append our content column names and create our SQL parameters. var valueSet = values.ValueSet(); var sqlParams = new Dictionary <string, object> (); var valueBuilder = new StringBuilder(); var index = 0L; foreach (var column in valueSet) { if (index > 0) { builder.Append(","); valueBuilder.Append(","); } builder.AppendFormat("{0}", column.Key); valueBuilder.AppendFormat("@{0}", column.Key); index++; sqlParams.Add(column.Key, column.Value); } builder.Append(") VALUES ("); builder.Append(valueBuilder); builder.Append(")"); var stmt = connection.Prepare(builder.ToString()); foreach (var p in sqlParams) { stmt.Bind(p.Key, p.Value); } return(stmt); }
/// <summary> /// Avoids the additional database trip that using SqliteCommandBuilder requires. /// </summary> /// <returns>The insert command.</returns> /// <param name="table">Table.</param> /// <param name="values">Values.</param> /// <param name="conflictResolutionStrategy">Conflict resolution strategy.</param> sqlite3_stmt GetInsertCommand(String table, ContentValues values, ConflictResolutionStrategy conflictResolutionStrategy) { var builder = new StringBuilder("INSERT"); if (conflictResolutionStrategy != ConflictResolutionStrategy.None) { builder.Append(" OR "); builder.Append(conflictResolutionStrategy); } builder.Append(" INTO "); builder.Append(table); builder.Append(" ("); // Append our content column names and create our SQL parameters. var valueSet = values.ValueSet(); var valueBuilder = new StringBuilder(); var index = 0; foreach (var column in valueSet) { if (index > 0) { builder.Append(","); valueBuilder.Append(","); } builder.AppendFormat("{0}", column.Key); valueBuilder.Append("@"); index++; } builder.Append(") VALUES ("); builder.Append(valueBuilder); builder.Append(")"); var sql = builder.ToString(); var command = Connection.Prepare(sql); index = 1; foreach (var val in valueSet) { var key = val.Key; command.Bind(index++, values[key]); } return(command); }
public async Task ResolveConflictsAsync(ConflictResolutionStrategy strategy) { var requestUriString = string.Format("{0}/synchronization/resolveConflicts?strategy={1}", baseUrl, Uri.EscapeDataString(strategy.ToString())); using (var request = RequestFactory.CreateHttpJsonRequest(new CreateHttpJsonRequestParams(this, requestUriString, HttpMethods.Patch, Credentials, Conventions)).AddOperationHeaders(OperationsHeaders)) { try { await request.ExecuteRequestAsync().ConfigureAwait(false); } catch (Exception e) { throw e.SimplifyException(); } } }
/// <summary> /// Avoids the additional database trip that using SqliteCommandBuilder requires. /// </summary> /// <returns>The insert command.</returns> /// <param name="table">Table.</param> /// <param name="values">Values.</param> /// <param name="conflictResolutionStrategy">Conflict resolution strategy.</param> SqliteCommand GetInsertCommand(String table, ContentValues values, ConflictResolutionStrategy conflictResolutionStrategy) { var builder = new StringBuilder("INSERT"); if (conflictResolutionStrategy != ConflictResolutionStrategy.None) { builder.Append(" OR "); builder.Append(conflictResolutionStrategy); } builder.Append(" INTO "); builder.Append(table); builder.Append(" ("); // Append our content column names and create our SQL parameters. var valueSet = values.ValueSet(); var sqlParams = new SqliteParameter[valueSet.LongCount()]; var valueBuilder = new StringBuilder(); var index = 0L; foreach (var column in valueSet) { if (index > 0) { builder.Append(","); valueBuilder.Append(","); } builder.AppendFormat("{0}", column.Key); valueBuilder.AppendFormat("@{0}", column.Key); sqlParams[index++] = new SqliteParameter(column.Key, column.Value); } builder.Append(") VALUES ("); builder.Append(valueBuilder); builder.Append(")"); var sql = builder.ToString(); var command = new SqliteCommand(sql, Connection, currentTransaction); command.Parameters.Clear(); command.Parameters.AddRange(sqlParams); return(command); }
public HttpResponseMessage ResolveConflicts(ConflictResolutionStrategy strategy) { IList <ConflictItem> conflicts = null; Storage.Batch(accessor => { int totalCount; var values = accessor.GetConfigsStartWithPrefix(RavenFileNameHelper.ConflictConfigNamePrefix, 0, int.MaxValue, out totalCount); conflicts = values.Select(x => JsonExtensions.JsonDeserialization <ConflictItem>(x)).ToList(); }); foreach (var conflict in conflicts) { ResolveConflict(conflict.FileName, strategy); } return(GetEmptyMessage(HttpStatusCode.NoContent)); }
void OpenSavedGame(ConflictResolutionStrategy strategy) { SetStandBy("Opening using strategy: " + strategy); PlayGamesPlatform.Instance.SavedGame.OpenWithAutomaticConflictResolution( mSavedGameFilename, DataSource.ReadNetworkOnly, strategy, (status, openedFile) => { mStatus = "Open status for file " + mSavedGameFilename + ": " + status + "\n"; if (openedFile != null) { mStatus += "Successfully opened file: " + openedFile.ToString(); Logger.d("Opened file: " + openedFile.ToString()); mCurrentSavedGame = openedFile; } EndStandBy(); }); }
public HttpResponseMessage ResolveConflict(string fileName, ConflictResolutionStrategy strategy) { Log.Debug("Resolving conflict of a file '{0}' by using {1} strategy", fileName, strategy); if (strategy == ConflictResolutionStrategy.CurrentVersion) { StrategyAsGetCurrent(fileName); } else if (strategy == ConflictResolutionStrategy.RemoteVersion) { StrategyAsGetRemote(fileName); } else { throw new NotSupportedException("NoOperation conflict resolution strategy, is not supported."); } return(GetEmptyMessage(HttpStatusCode.NoContent)); }
public SynchronizationThread(NoteRepository repository, IEnumerable <ISynchronizationFeedback> synclistener, AppSettings settings, IAlephDispatcher disp) { _repo = repository; _listener = synclistener.ToList(); _conflictStrategy = ConflictResolutionStrategyHelper.ToInterfaceType(settings.ConflictResolution); _noteDownloadEnableMultithreading = repository.SupportsDownloadMultithreading; _noteDownloadParallelismLevel = settings.NoteDownloadParallelismLevel; _noteDownloadParallelismThreshold = settings.NoteDownloadParallelismThreshold; _noteNewDownloadEnableMultithreading = repository.SupportsNewDownloadMultithreading; _noteNewDownloadParallelismLevel = settings.NoteNewDownloadParallelismLevel; _noteNewDownloadParallelismThreshold = settings.NoteNewDownloadParallelismThreshold; _noteUploadEnableMultithreading = repository.SupportsUploadMultithreading; _noteUploadParallelismLevel = settings.NoteUploadParallelismLevel; _noteUploadParallelismThreshold = settings.NoteUploadParallelismThreshold; _dispatcher = disp; _comChannel = new ManualResetEvent(false); }
public bool TryResolveConflict(string fileName, ConflictItem conflict, RavenJObject localMetadata, RavenJObject remoteMetadata, out ConflictResolutionStrategy strategy) { foreach (var resolver in Resolvers) { if (resolver.TryResolve(fileName, localMetadata, remoteMetadata, out strategy) == false) continue; switch (strategy) { case ConflictResolutionStrategy.CurrentVersion: ApplyCurrentStrategy(fileName, conflict, localMetadata); return true; case ConflictResolutionStrategy.RemoteVersion: ApplyRemoteStrategy(fileName, conflict, localMetadata); return true; } } strategy = ConflictResolutionStrategy.NoResolution; return false; }
public long InsertWithOnConflict(String table, String nullColumnHack, ContentValues initialValues, ConflictResolutionStrategy conflictResolutionStrategy) { if (!StringEx.IsNullOrWhiteSpace(nullColumnHack)) { var e = new InvalidOperationException("{0} does not support the 'nullColumnHack'.".Fmt(TAG)); Log.E(TAG, "Unsupported use of nullColumnHack", e); throw e; } var t = Factory.StartNew(() => { var lastInsertedId = -1L; var command = GetInsertCommand(table, initialValues, conflictResolutionStrategy); try { LastErrorCode = command.step(); command.Dispose(); if (LastErrorCode == SQLiteResult.ERROR) throw new CouchbaseLiteException(raw.sqlite3_errmsg(_writeConnection), StatusCode.DbError); int changes = _writeConnection.changes(); if (changes > 0) { lastInsertedId = _writeConnection.last_insert_rowid(); } if (lastInsertedId == -1L) { if(conflictResolutionStrategy != ConflictResolutionStrategy.Ignore) { Log.E(TAG, "Error inserting " + initialValues + " using " + command); throw new CouchbaseLiteException("Error inserting " + initialValues + " using " + command, StatusCode.DbError); } } else { Log.V(TAG, "Inserting row {0} into {1} with values {2}", lastInsertedId, table, initialValues); } } catch (Exception ex) { Log.E(TAG, "Error inserting into table " + table, ex); LastErrorCode = raw.sqlite3_errcode(_writeConnection); throw; } return lastInsertedId; }); var r = t.ConfigureAwait(false).GetAwaiter().GetResult(); if (t.Exception != null) throw t.Exception; return r; }
/// <summary> /// Avoids the additional database trip that using SqliteCommandBuilder requires. /// </summary> /// <returns>The insert command.</returns> /// <param name="table">Table.</param> /// <param name="values">Values.</param> /// <param name="conflictResolutionStrategy">Conflict resolution strategy.</param> SqliteCommand GetInsertCommand (String table, ContentValues values, ConflictResolutionStrategy conflictResolutionStrategy) { var builder = new StringBuilder("INSERT"); if (conflictResolutionStrategy != ConflictResolutionStrategy.None) { builder.Append(" OR "); builder.Append(conflictResolutionStrategy); } builder.Append(" INTO "); builder.Append(table); builder.Append(" ("); // Append our content column names and create our SQL parameters. var valueSet = values.ValueSet(); var sqlParams = new SqliteParameter[valueSet.LongCount()]; var valueBuilder = new StringBuilder(); var index = 0L; foreach(var column in valueSet) { if (index > 0) { builder.Append(","); valueBuilder.Append(","); } builder.AppendFormat( "{0}", column.Key); valueBuilder.AppendFormat("@{0}", column.Key); sqlParams[index++] = new SqliteParameter(column.Key, column.Value); } builder.Append(") VALUES ("); builder.Append(valueBuilder); builder.Append(")"); var sql = builder.ToString(); var command = new SqliteCommand(sql, Connection, currentTransaction); command.Parameters.Clear(); command.Parameters.AddRange(sqlParams); return command; }
public override RemoteUploadResult UploadNoteToRemote(ref INote note, out INote conflict, out bool keepNoteRemoteDirtyWithConflict, ConflictResolutionStrategy strategy) { conflict = null; keepNoteRemoteDirtyWithConflict = false; return(RemoteUploadResult.UpToDate); }
public long InsertWithOnConflict (String table, String nullColumnHack, ContentValues initialValues, ConflictResolutionStrategy conflictResolutionStrategy) { if (!String.IsNullOrWhiteSpace(nullColumnHack)) { var e = new InvalidOperationException("{0} does not support the 'nullColumnHack'.".Fmt(Tag)); Log.E(Tag, "Unsupported use of nullColumnHack", e); throw e; } var command = GetInsertCommand(table, initialValues, conflictResolutionStrategy); var lastInsertedId = -1L; try { var result = command.Step(); // Get the new row's id. // TODO.ZJG: This query should ultimately be replaced with a call to sqlite3_last_insert_rowid. var lastInsertedIndexCommand = Connection.Prepare("select last_insert_rowid()"); var rowidResult = lastInsertedIndexCommand.Step(); if (rowidResult != SQLiteResult.ERROR) throw new CouchbaseLiteException(lastInsertedIndexCommand.Connection.ErrorMessage(), StatusCode.DbError); lastInsertedId = Convert.ToInt64(lastInsertedIndexCommand[0]); lastInsertedIndexCommand.Dispose(); if (lastInsertedId == -1L) { Log.E(Tag, "Error inserting " + initialValues + " using " + command); } else { Log.V(Tag, "Inserting row " + lastInsertedId + " from " + initialValues + " using " + command); } } catch (Exception ex) { Log.E(Tag, "Error inserting into table " + table, ex); } finally { command.Dispose(); } return lastInsertedId; }
private void InternalOpen(string filename, DataSource source, ConflictResolutionStrategy resolutionStrategy, bool prefetchDataOnConflict, ConflictCallback conflictCallback, Action <SavedGameRequestStatus, ISavedGameMetadata> completedCallback) { int conflictPolicy; // SnapshotsClient.java#RetentionPolicy switch (resolutionStrategy) { case ConflictResolutionStrategy.UseLastKnownGood: conflictPolicy = 2 /* RESOLUTION_POLICY_LAST_KNOWN_GOOD */; break; case ConflictResolutionStrategy.UseMostRecentlySaved: conflictPolicy = 3 /* RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED */; break; case ConflictResolutionStrategy.UseLongestPlaytime: conflictPolicy = 1 /* RESOLUTION_POLICY_LONGEST_PLAYTIME*/; break; case ConflictResolutionStrategy.UseManual: conflictPolicy = -1 /* RESOLUTION_POLICY_MANUAL */; break; default: conflictPolicy = 3 /* RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED */; break; } using (var task = mSnapshotsClient.Call <AndroidJavaObject>("open", filename, /* createIfNotFound= */ true, conflictPolicy)) { AndroidTaskUtils.AddOnSuccessListener <AndroidJavaObject>( task, dataOrConflict => { if (dataOrConflict.Call <bool>("isConflict")) { var conflict = dataOrConflict.Call <AndroidJavaObject>("getConflict"); AndroidSnapshotMetadata original = new AndroidSnapshotMetadata(conflict.Call <AndroidJavaObject>("getSnapshot")); AndroidSnapshotMetadata unmerged = new AndroidSnapshotMetadata( conflict.Call <AndroidJavaObject>("getConflictingSnapshot")); // Instantiate the conflict resolver. Note that the retry callback closes over // all the parameters we need to retry the open attempt. Once the conflict is // resolved by invoking the appropriate resolution method on // AndroidConflictResolver, the resolver will invoke this callback, which will // result in this method being re-executed. This recursion will continue until // all conflicts are resolved or an error occurs. AndroidConflictResolver resolver = new AndroidConflictResolver( this, mSnapshotsClient, conflict, original, unmerged, completedCallback, () => InternalOpen(filename, source, resolutionStrategy, prefetchDataOnConflict, conflictCallback, completedCallback)); var originalBytes = original.JavaContents.Call <byte[]>("readFully"); var unmergedBytes = unmerged.JavaContents.Call <byte[]>("readFully"); conflictCallback(resolver, original, originalBytes, unmerged, unmergedBytes); } else { using (var snapshot = dataOrConflict.Call <AndroidJavaObject>("getData")) { AndroidJavaObject metadata = snapshot.Call <AndroidJavaObject>("freeze"); completedCallback(SavedGameRequestStatus.Success, new AndroidSnapshotMetadata(metadata)); } } }); AddOnFailureListenerWithSignOut( task, exception => { OurUtils.Logger.d("InternalOpen has failed: " + exception.Call <string>("toString")); var status = mAndroidClient.IsAuthenticated() ? SavedGameRequestStatus.InternalError : SavedGameRequestStatus.AuthenticationError; completedCallback(status, null); } ); } }
public long InsertWithOnConflict(String table, String nullColumnHack, ContentValues initialValues, ConflictResolutionStrategy conflictResolutionStrategy) { if (!String.IsNullOrWhiteSpace(nullColumnHack)) { var e = new InvalidOperationException("{0} does not support the 'nullColumnHack'.".Fmt(Tag)); Log.E(Tag, "Unsupported use of nullColumnHack", e); throw e; } var command = GetInsertCommand(table, initialValues, conflictResolutionStrategy); var lastInsertedId = -1L; try { var result = command.Step(); // Get the new row's id. // TODO.ZJG: This query should ultimately be replaced with a call to sqlite3_last_insert_rowid. var lastInsertedIndexCommand = Connection.Prepare("select last_insert_rowid()"); var rowidResult = lastInsertedIndexCommand.Step(); if (rowidResult != SQLiteResult.ERROR) { throw new CouchbaseLiteException(lastInsertedIndexCommand.Connection.ErrorMessage(), StatusCode.DbError); } lastInsertedId = Convert.ToInt64(lastInsertedIndexCommand[0]); lastInsertedIndexCommand.Dispose(); if (lastInsertedId == -1L) { Log.E(Tag, "Error inserting " + initialValues + " using " + command); } else { Log.V(Tag, "Inserting row " + lastInsertedId + " from " + initialValues + " using " + command); } } catch (Exception ex) { Log.E(Tag, "Error inserting into table " + table, ex); } finally { command.Dispose(); } return(lastInsertedId); }
public long InsertWithOnConflict(String table, String nullColumnHack, ContentValues initialValues, ConflictResolutionStrategy conflictResolutionStrategy) { if (_readOnly) { throw Misc.CreateExceptionAndLog(Log.To.Database, StatusCode.Forbidden, TAG, "Attempting to write to a readonly database"); } if (!StringEx.IsNullOrWhiteSpace(nullColumnHack)) { throw new InvalidOperationException("Don't use nullColumnHack"); } Log.To.TaskScheduling.V(TAG, "Scheduling InsertWithOnConflict"); var t = Factory.StartNew(() => { Log.To.TaskScheduling.V(TAG, "Running InsertWithOnConflict"); var lastInsertedId = -1L; var command = GetInsertCommand(table, initialValues, conflictResolutionStrategy); try { LastErrorCode = command.step(); command.Dispose(); if (LastErrorCode == raw.SQLITE_ERROR) { throw Misc.CreateExceptionAndLog(Log.To.Database, StatusCode.DbError, TAG, raw.sqlite3_errmsg(_writeConnection)); } int changes = _writeConnection.changes(); if (changes > 0) { lastInsertedId = _writeConnection.last_insert_rowid(); } if (lastInsertedId == -1L) { if(conflictResolutionStrategy != ConflictResolutionStrategy.Ignore) { throw Misc.CreateExceptionAndLog(Log.To.Database, StatusCode.DbError, TAG, "Error inserting {0} using {1}", initialValues, command); } } else { Log.To.Database.V(TAG, "Inserting row {0} into {1} with values {2}", lastInsertedId, table, initialValues); } } catch(CouchbaseLiteException) { LastErrorCode = raw.sqlite3_errcode(_writeConnection); Log.To.Database.E(TAG, "Error inserting into table {0}, rethrowing...", table); throw; } catch (Exception ex) { LastErrorCode = raw.sqlite3_errcode(_writeConnection); throw Misc.CreateExceptionAndLog(Log.To.Database, ex, StatusCode.DbError, TAG, "Error inserting into table {0}", table); } return lastInsertedId; }); var r = t.ConfigureAwait(false).GetAwaiter().GetResult(); if (t.Exception != null) throw t.Exception; return r; }
public bool TryResolveConflict(string fileName, ConflictItem conflict, RavenJObject localMetadata, RavenJObject remoteMetadata, out ConflictResolutionStrategy strategy) { foreach (var resolver in Resolvers) { if (resolver.TryResolve(fileName, localMetadata, remoteMetadata, out strategy) == false) { continue; } switch (strategy) { case ConflictResolutionStrategy.CurrentVersion: ApplyCurrentStrategy(fileName, conflict, localMetadata); return(true); case ConflictResolutionStrategy.RemoteVersion: ApplyRemoteStrategy(fileName, conflict, localMetadata); return(true); } } strategy = ConflictResolutionStrategy.NoResolution; return(false); }
public override long InsertWithOnConflict (String table, String nullColumnHack, ContentValues initialValues, ConflictResolutionStrategy conflictResolutionStrategy) { if (!String.IsNullOrWhiteSpace(nullColumnHack)) { var e = new InvalidOperationException("{0} does not support the 'nullColumnHack'.".Fmt(Tag)); Log.E(Tag, "Unsupported use of nullColumnHack", e); throw e; } var command = GetInsertCommand(table, initialValues, conflictResolutionStrategy); var lastInsertedId = -1L; try { command.ExecuteNonQuery(); // Get the new row's id. // TODO.ZJG: This query should ultimately be replaced with a call to sqlite3_last_insert_rowid. var lastInsertedIndexCommand = new SqliteCommand("select last_insert_rowid()", Connection, currentTransaction); lastInsertedId = (Int64)lastInsertedIndexCommand.ExecuteScalar(); lastInsertedIndexCommand.Dispose(); if (lastInsertedId == -1L) { Log.E(Tag, "Error inserting " + initialValues + " using " + command.CommandText); } else { Log.V(Tag, "Inserting row " + lastInsertedId + " from " + initialValues + " using " + command.CommandText); } } catch (Exception ex) { Log.E(Tag, "Error inserting into table " + table, ex); } finally { command.Dispose(); } return lastInsertedId; }
internal void OpenSavedGame(ConflictResolutionStrategy strategy) { SetStandBy("Opening using strategy: " + strategy); PlayGamesPlatform.Instance.SavedGame.OpenWithAutomaticConflictResolution( mSavedGameFilename, DataSource.ReadNetworkOnly, strategy, (status, openedFile) => { mStatus = "Open status for file " + mSavedGameFilename + ": " + status + "\n"; if (openedFile != null) { mStatus += "Successfully opened file: " + openedFile.ToString(); Logger.d("Opened file: " + openedFile.ToString()); mCurrentSavedGame = openedFile; } EndStandBy(); }); }
public async Task ResolveConflictAsync(string filename, ConflictResolutionStrategy strategy) { var requestUriString = string.Format("{0}/synchronization/resolveConflict/{1}?strategy={2}", baseUrl, Uri.EscapeDataString(filename), Uri.EscapeDataString(strategy.ToString())); using (var request = RequestFactory.CreateHttpJsonRequest(new CreateHttpJsonRequestParams(this, requestUriString, "PATCH", Credentials, Conventions)).AddOperationHeaders(OperationsHeaders)) { try { await request.ExecuteRequestAsync().ConfigureAwait(false); } catch (Exception e) { throw e.SimplifyException(); } } }
public override RemoteUploadResult UploadNoteToRemote(ref INote inote, out INote conflict, ConflictResolutionStrategy strategy) { FilesystemNote note = (FilesystemNote)inote; var path = note.GetPath(_config); if (File.Exists(note.PathRemote) && path != note.PathRemote && !File.Exists(path)) { _logger.Debug(FilesystemPlugin.Name, "Upload note to changed remote path"); // path changed and new path does not exist WriteNoteToPath(note, path); conflict = null; ANFileSystemUtil.DeleteFileAndFolderIfEmpty(FilesystemPlugin.Name, _logger, _config.Folder, note.PathRemote); note.PathRemote = path; return(RemoteUploadResult.Uploaded); } else if (File.Exists(note.PathRemote) && path != note.PathRemote && File.Exists(path)) { _logger.Debug(FilesystemPlugin.Name, "Upload note to changed remote path"); // path changed and new path does exist var conf = ReadNoteFromPath(note.PathRemote); if (conf.ModificationDate > note.ModificationDate) { conflict = conf; if (strategy == ConflictResolutionStrategy.UseClientCreateConflictFile || strategy == ConflictResolutionStrategy.UseClientVersion || strategy == ConflictResolutionStrategy.ManualMerge) { WriteNoteToPath(note, path); ANFileSystemUtil.DeleteFileAndFolderIfEmpty(FilesystemPlugin.Name, _logger, _config.Folder, note.PathRemote); note.PathRemote = path; return(RemoteUploadResult.Conflict); } else { note.PathRemote = path; return(RemoteUploadResult.Conflict); } } else { WriteNoteToPath(note, path); conflict = null; ANFileSystemUtil.DeleteFileAndFolderIfEmpty(FilesystemPlugin.Name, _logger, _config.Folder, note.PathRemote); note.PathRemote = path; return(RemoteUploadResult.Uploaded); } } else if (File.Exists(path)) // normal update { var conf = ReadNoteFromPath(path); if (conf.ModificationDate > note.ModificationDate) { conflict = conf; if (strategy == ConflictResolutionStrategy.UseClientCreateConflictFile || strategy == ConflictResolutionStrategy.UseClientVersion) { WriteNoteToPath(note, path); if (note.PathRemote != "") { ANFileSystemUtil.DeleteFileAndFolderIfEmpty(FilesystemPlugin.Name, _logger, _config.Folder, note.PathRemote); } note.PathRemote = path; return(RemoteUploadResult.Conflict); } else { note.PathRemote = path; return(RemoteUploadResult.Conflict); } } else { WriteNoteToPath(note, path); conflict = null; note.PathRemote = path; return(RemoteUploadResult.Uploaded); } } else // new file { WriteNoteToPath(note, path); conflict = null; note.PathRemote = path; return(RemoteUploadResult.Uploaded); } }
public override long InsertWithOnConflict (string table, string nullColumnHack, ContentValues initialValues, ConflictResolutionStrategy conflictResolutionStrategy) { throw new NotImplementedException (); }
public override bool TryResolve(string fileName, RavenJObject localMedatada, RavenJObject remoteMetadata, out ConflictResolutionStrategy resolutionStrategy) { resolutionStrategy = ConflictResolutionStrategy.RemoteVersion; return true; }
/// <summary> /// Avoids the additional database trip that using SqliteCommandBuilder requires. /// </summary> /// <returns>The insert command.</returns> /// <param name="table">Table.</param> /// <param name="values">Values.</param> /// <param name="conflictResolutionStrategy">Conflict resolution strategy.</param> sqlite3_stmt GetInsertCommand(String table, ContentValues values, ConflictResolutionStrategy conflictResolutionStrategy) { if (!IsOpen) { throw Misc.CreateExceptionAndLog(Log.To.Database, StatusCode.BadRequest, TAG, "GetInsertCommand called on closed database"); } var builder = new StringBuilder("INSERT"); if (conflictResolutionStrategy != ConflictResolutionStrategy.None) { builder.Append(" OR "); builder.Append(conflictResolutionStrategy); } builder.Append(" INTO "); builder.Append(table); builder.Append(" ("); // Append our content column names and create our SQL parameters. var valueSet = values.ValueSet(); var valueBuilder = new StringBuilder(); var index = 0; var args = new object[valueSet.Count]; foreach (var column in valueSet) { if (index > 0) { builder.Append(","); valueBuilder.Append(","); } builder.AppendFormat("{0}", column.Key); valueBuilder.Append("?"); args[index] = column.Value; index++; } builder.Append(") VALUES ("); builder.Append(valueBuilder); builder.Append(")"); var sql = builder.ToString(); sqlite3_stmt command = null; if (args != null) { Log.To.Database.V(TAG, "Preparing statement: '{0}' with values: {1}", sql, new SecureLogJsonString(args, LogMessageSensitivity.PotentiallyInsecure)); } else { Log.To.Database.V(TAG, "Preparing statement: '{0}'", sql); } command = BuildCommand(_writeConnection, sql, args); return command; }
public override RemoteUploadResult UploadNoteToRemote(ref INote inote, out INote conflict, ConflictResolutionStrategy strategy) { var note = (EvernoteNote)inote; var remote = bucket.Notes.FirstOrDefault(p => Guid.Parse(p.Guid) == note.ID); remoteDirty = true; if (remote == null) { inote = APICreateNewNote(note); conflict = null; return(RemoteUploadResult.Uploaded); } else { if (remote.UpdateSequenceNum > note.UpdateSequenceNumber) { if (strategy == ConflictResolutionStrategy.UseClientVersion || strategy == ConflictResolutionStrategy.UseClientCreateConflictFile || strategy == ConflictResolutionStrategy.ManualMerge) { conflict = APIDownloadNote(note.ID); inote = APIUpdateNote(note); return(RemoteUploadResult.Conflict); } else if (strategy == ConflictResolutionStrategy.UseServerVersion || strategy == ConflictResolutionStrategy.UseServerCreateConflictFile) { conflict = inote.Clone(); inote = APIDownloadNote(note.ID); return(RemoteUploadResult.Conflict); } else { throw new ArgumentException("strategy == " + strategy); } } else { inote = APIUpdateNote(note); conflict = null; return(RemoteUploadResult.Uploaded); } } }
public void OpenWithAutomaticConflictResolution(string filename, DataSource source, ConflictResolutionStrategy resolutionStrategy, Action <SavedGameRequestStatus, ISavedGameMetadata> completedCallback) { OpenWithAutomaticConflictResolution(filename, source, resolutionStrategy, false, null, completedCallback); }
public void OpenWithAutomaticConflictResolution(string filename, DataSource source, ConflictResolutionStrategy resolutionStrategy, Action<SavedGameRequestStatus, ISavedGameMetadata> callback) { throw new NotImplementedException(mMessage); }
private void InternalOpen(string filename, DataSource source, ConflictResolutionStrategy resolutionStrategy, bool prefetchDataOnConflict, ConflictCallback conflictCallback, Action <SavedGameRequestStatus, ISavedGameMetadata> completedCallback) { Types.SnapshotConflictPolicy policy; switch (resolutionStrategy) { case ConflictResolutionStrategy.UseLastKnownGood: policy = Types.SnapshotConflictPolicy.LAST_KNOWN_GOOD; break; case ConflictResolutionStrategy.UseMostRecentlySaved: policy = Types.SnapshotConflictPolicy.MOST_RECENTLY_MODIFIED; break; case ConflictResolutionStrategy.UseLongestPlaytime: policy = Types.SnapshotConflictPolicy.LONGEST_PLAYTIME; break; case ConflictResolutionStrategy.UseManual: policy = Types.SnapshotConflictPolicy.MANUAL; break; default: policy = Types.SnapshotConflictPolicy.MOST_RECENTLY_MODIFIED; break; } mSnapshotManager.Open(filename, AsDataSource(source), policy, response => { if (!response.RequestSucceeded()) { completedCallback(AsRequestStatus(response.ResponseStatus()), null); } else if (response.ResponseStatus() == Status.SnapshotOpenStatus.VALID) { completedCallback(SavedGameRequestStatus.Success, response.Data()); } else if (response.ResponseStatus() == Status.SnapshotOpenStatus.VALID_WITH_CONFLICT) { // If we get here, manual conflict resolution is required. NativeSnapshotMetadata original = response.ConflictOriginal(); NativeSnapshotMetadata unmerged = response.ConflictUnmerged(); // Instantiate the conflict resolver. Note that the retry callback closes over // all the parameters we need to retry the open attempt. Once the conflict is // resolved by invoking the appropriate resolution method on // NativeConflictResolver, the resolver will invoke this callback, which will // result in this method being re-executed. This recursion will continue until // all conflicts are resolved or an error occurs. NativeConflictResolver resolver = new NativeConflictResolver( mSnapshotManager, response.ConflictId(), original, unmerged, completedCallback, () => InternalOpen(filename, source, resolutionStrategy, prefetchDataOnConflict, conflictCallback, completedCallback) ); // If we don't have to pre-fetch the saved games' binary data, we can // immediately invoke the conflict callback. Note that this callback is // constructed to execute on the game thread in // OpenWithManualConflictResolution. if (!prefetchDataOnConflict) { conflictCallback(resolver, original, null, unmerged, null); return; } // If we have to prefetch the data, we delegate invoking the conflict resolution // callback to the joiner instance (once both callbacks resolve, the joiner will // invoke the lambda that we declare here, using the fetched data). Prefetcher joiner = new Prefetcher((originalData, unmergedData) => conflictCallback(resolver, original, originalData, unmerged, unmergedData), completedCallback); // Kick off the read calls. mSnapshotManager.Read(original, joiner.OnOriginalDataRead); mSnapshotManager.Read(unmerged, joiner.OnUnmergedDataRead); } else { Logger.e("Unhandled response status"); completedCallback(SavedGameRequestStatus.InternalError, null); } }); }
public abstract long InsertWithOnConflict(string table, string nullColumnHack, ContentValues initialValues, ConflictResolutionStrategy conflictResolutionStrategy);
public long InsertWithOnConflict (String table, String nullColumnHack, ContentValues initialValues, ConflictResolutionStrategy conflictResolutionStrategy) { if (!String.IsNullOrWhiteSpace(nullColumnHack)) { var e = new InvalidOperationException("{0} does not support the 'nullColumnHack'.".Fmt(Tag)); Log.E(Tag, "Unsupported use of nullColumnHack", e); throw e; } var lastInsertedId = -1L; var command = GetInsertCommand(table, initialValues, conflictResolutionStrategy); try { int result; lock (dbLock) { result = command.step (); } if (result == SQLiteResult.ERROR) throw new CouchbaseLiteException(raw.sqlite3_errmsg(db), StatusCode.DbError); int changes; lock (dbLock) { changes = db.changes (); } if (changes > 0) { lock (dbLock) { lastInsertedId = db.last_insert_rowid(); } } if (lastInsertedId == -1L) { Log.E(Tag, "Error inserting " + initialValues + " using " + command); throw new CouchbaseLiteException("Error inserting " + initialValues + " using " + command, StatusCode.DbError); } else { Log.V(Tag, "Inserting row {0} into {1} with values {2}", lastInsertedId, table, initialValues); } } catch (Exception ex) { Log.E(Tag, "Error inserting into table " + table, ex); throw; } finally { lock (dbLock) { command.Dispose(); } } return lastInsertedId; }
public override RemoteUploadResult UploadNoteToRemote(ref INote inote, out INote conflict, ConflictResolutionStrategy strategy) { using (var web = CreateAuthenticatedClient()) { var note = (SimpleNote)inote; var remote = buckets.index.FirstOrDefault(p => p.id == note.ID); if (remote == null) { conflict = null; inote = SimpleNoteAPI.UploadNewNote(web, note, _config, this); return(RemoteUploadResult.Uploaded); } else { if (remote.v > note.LocalVersion) { if (strategy == ConflictResolutionStrategy.UseClientVersion || strategy == ConflictResolutionStrategy.UseClientCreateConflictFile || strategy == ConflictResolutionStrategy.ManualMerge) { conflict = SimpleNoteAPI.GetNoteData(web, note.ID, _config, this); inote = SimpleNoteAPI.ChangeExistingNote(web, note, _config, this, out _); return(RemoteUploadResult.Conflict); } else if (strategy == ConflictResolutionStrategy.UseServerVersion || strategy == ConflictResolutionStrategy.UseServerCreateConflictFile) { conflict = inote.Clone(); inote = SimpleNoteAPI.GetNoteData(web, note.ID, _config, this); return(RemoteUploadResult.Conflict); } else { throw new ArgumentException("strategy == " + strategy); } } else { conflict = null; bool updated; inote = SimpleNoteAPI.ChangeExistingNote(web, note, _config, this, out updated); return(updated ? RemoteUploadResult.Uploaded : RemoteUploadResult.UpToDate); } } } }
public HttpResponseMessage ResolveConflict(string fileName, ConflictResolutionStrategy strategy) { Log.Debug("Resolving conflict of a file '{0}' by using {1} strategy", fileName, strategy); if (strategy == ConflictResolutionStrategy.CurrentVersion) { StrategyAsGetCurrent(fileName); } else { StrategyAsGetRemote(fileName); } return new HttpResponseMessage(HttpStatusCode.OK); }
/// <summary> /// Avoids the additional database trip that using SqliteCommandBuilder requires. /// </summary> /// <returns>The insert command.</returns> /// <param name="table">Table.</param> /// <param name="values">Values.</param> /// <param name="conflictResolutionStrategy">Conflict resolution strategy.</param> sqlite3_stmt GetInsertCommand (String table, ContentValues values, ConflictResolutionStrategy conflictResolutionStrategy) { var builder = new StringBuilder("INSERT"); if (conflictResolutionStrategy != ConflictResolutionStrategy.None) { builder.Append(" OR "); builder.Append(conflictResolutionStrategy); } builder.Append(" INTO "); builder.Append(table); builder.Append(" ("); // Append our content column names and create our SQL parameters. var valueSet = values.ValueSet(); var valueBuilder = new StringBuilder(); var index = 0; foreach(var column in valueSet) { if (index > 0) { builder.Append(","); valueBuilder.Append(","); } builder.AppendFormat( "{0}", column.Key); valueBuilder.Append("@"); index++; } builder.Append(") VALUES ("); builder.Append(valueBuilder); builder.Append(")"); var sql = builder.ToString(); var command = Connection.Prepare(sql); index = 1; foreach(var val in valueSet) { var key = val.Key; command.Bind(index++, values[key]); } return command; }
/// <summary> /// Avoids the additional database trip that using SqliteCommandBuilder requires. /// </summary> /// <returns>The insert command.</returns> /// <param name="table">Table.</param> /// <param name="values">Values.</param> /// <param name="conflictResolutionStrategy">Conflict resolution strategy.</param> sqlite3_stmt GetInsertCommand (String table, ContentValues values, ConflictResolutionStrategy conflictResolutionStrategy) { if (!IsOpen) { Open(Path); } var builder = new StringBuilder("INSERT"); if (conflictResolutionStrategy != ConflictResolutionStrategy.None) { builder.Append(" OR "); builder.Append(conflictResolutionStrategy); } builder.Append(" INTO "); builder.Append(table); builder.Append(" ("); // Append our content column names and create our SQL parameters. var valueSet = values.ValueSet(); var valueBuilder = new StringBuilder(); var index = 0; var args = new object[valueSet.Count]; foreach(var column in valueSet) { if (index > 0) { builder.Append(","); valueBuilder.Append(","); } builder.AppendFormat( "{0}", column.Key); valueBuilder.Append("?"); args[index] = column.Value; index++; } builder.Append(") VALUES ("); builder.Append(valueBuilder); builder.Append(")"); var sql = builder.ToString(); sqlite3_stmt command; lock (dbLock) { command = db.prepare (sql); command.bind (args); } return command; }
public override bool TryResolve(string fileName, RavenJObject localMedatada, RavenJObject remoteMetadata, out ConflictResolutionStrategy resolutionStrategy) { resolutionStrategy = ConflictResolutionStrategy.CurrentVersion; return(true); }
public abstract bool TryResolve(string fileName, RavenJObject localMedatada, RavenJObject remoteMetadata, out ConflictResolutionStrategy resolutionStrategy);
/// <summary> /// Avoids the additional database trip that using SqliteCommandBuilder requires. /// </summary> /// <returns>The insert command.</returns> /// <param name="table">Table.</param> /// <param name="values">Values.</param> /// <param name="conflictResolutionStrategy">Conflict resolution strategy.</param> sqlite3_stmt GetInsertCommand(String table, ContentValues values, ConflictResolutionStrategy conflictResolutionStrategy) { if (!IsOpen) { throw Misc.CreateExceptionAndLog(Log.To.Database, StatusCode.BadRequest, TAG, "GetInsertCommand called on closed database"); } var builder = new StringBuilder("INSERT"); if (conflictResolutionStrategy != ConflictResolutionStrategy.None) { builder.Append(" OR "); builder.Append(conflictResolutionStrategy); } builder.Append(" INTO "); builder.Append(table); builder.Append(" ("); // Append our content column names and create our SQL parameters. var valueSet = values.ValueSet(); var valueBuilder = new StringBuilder(); var index = 0; var args = new object[valueSet.Count]; foreach (var column in valueSet) { if (index > 0) { builder.Append(","); valueBuilder.Append(","); } builder.AppendFormat("{0}", column.Key); valueBuilder.Append("?"); args[index] = column.Value; index++; } builder.Append(") VALUES ("); builder.Append(valueBuilder); builder.Append(")"); var sql = builder.ToString(); sqlite3_stmt command = null; if (args != null) { Log.To.Database.V(TAG, "Preparing statement: '{0}' with values: {1}", sql, new SecureLogJsonString(args, LogMessageSensitivity.PotentiallyInsecure)); } else { Log.To.Database.V(TAG, "Preparing statement: '{0}'", sql); } command = BuildCommand(_writeConnection, sql, args); return(command); }
public void OpenWithAutomaticConflictResolution(string filename, DataSource source, ConflictResolutionStrategy resolutionStrategy, Action <SavedGameRequestStatus, ISavedGameMetadata> callback) { throw new NotImplementedException(mMessage); }
/// <summary> /// Avoids the additional database trip that using SqliteCommandBuilder requires. /// </summary> /// <returns>The insert command.</returns> /// <param name="table">Table.</param> /// <param name="values">Values.</param> /// <param name="conflictResolutionStrategy">Conflict resolution strategy.</param> sqlite3_stmt GetInsertCommand(String table, ContentValues values, ConflictResolutionStrategy conflictResolutionStrategy) { if (!IsOpen) { Open(Path); } var builder = new StringBuilder("INSERT"); if (conflictResolutionStrategy != ConflictResolutionStrategy.None) { builder.Append(" OR "); builder.Append(conflictResolutionStrategy); } builder.Append(" INTO "); builder.Append(table); builder.Append(" ("); // Append our content column names and create our SQL parameters. var valueSet = values.ValueSet(); var valueBuilder = new StringBuilder(); var index = 0; var args = new object[valueSet.Count]; foreach (var column in valueSet) { if (index > 0) { builder.Append(","); valueBuilder.Append(","); } builder.AppendFormat("{0}", column.Key); valueBuilder.Append("?"); args[index] = column.Value; index++; } builder.Append(") VALUES ("); builder.Append(valueBuilder); builder.Append(")"); var sql = builder.ToString(); sqlite3_stmt command = null; if (args != null) { Log.D(TAG, "Preparing statement: '{0}' with values: {1}", sql, String.Join(", ", args.Select(o => o == null ? "null" : o.ToString()).ToArray())); } else { Log.D(TAG, "Preparing statement: '{0}'", sql); } command = BuildCommand(_writeConnection, sql, args); return command; }
/// <summary> /// Avoids the additional database trip that using SqliteCommandBuilder requires. /// </summary> /// <returns>The insert command.</returns> /// <param name="table">Table.</param> /// <param name="values">Values.</param> /// <param name="conflictResolutionStrategy">Conflict resolution strategy.</param> ISQLiteStatement GetInsertCommand (String table, ContentValues values, ConflictResolutionStrategy conflictResolutionStrategy) { var builder = new StringBuilder("INSERT"); if (conflictResolutionStrategy != ConflictResolutionStrategy.None) { builder.Append(" OR "); builder.Append(conflictResolutionStrategy); } builder.Append(" INTO "); builder.Append(table); builder.Append(" ("); // Append our content column names and create our SQL parameters. var valueSet = values.ValueSet(); var sqlParams = new Dictionary<string, object> (); var valueBuilder = new StringBuilder(); var index = 0L; foreach(var column in valueSet) { if (index > 0) { builder.Append(","); valueBuilder.Append(","); } builder.AppendFormat( "{0}", column.Key); valueBuilder.AppendFormat("@{0}", column.Key); index++; sqlParams.Add (column.Key, column.Value); } builder.Append(") VALUES ("); builder.Append(valueBuilder); builder.Append(")"); var stmt = connection.Prepare (builder.ToString ()); foreach (var p in sqlParams) stmt.Bind (p.Key, p.Value); return stmt; }
public HttpResponseMessage ResolveConflict(string filename, ConflictResolutionStrategy strategy) { var canonicalFilename = FileHeader.Canonize(filename); Log.Debug("Resolving conflict of a file '{0}' by using {1} strategy", filename, strategy); switch (strategy) { case ConflictResolutionStrategy.CurrentVersion: Storage.Batch(accessor => { var localMetadata = accessor.GetFile(canonicalFilename, 0, 0).Metadata; var conflict = accessor.GetConfigurationValue<ConflictItem>(RavenFileNameHelper.ConflictConfigNameForFile(canonicalFilename)); ConflictResolver.ApplyCurrentStrategy(canonicalFilename, conflict, localMetadata); accessor.UpdateFileMetadata(canonicalFilename, localMetadata, null); ConflictArtifactManager.Delete(canonicalFilename, accessor); }); Publisher.Publish(new ConflictNotification { FileName = filename, Status = ConflictStatus.Resolved }); break; case ConflictResolutionStrategy.RemoteVersion: Storage.Batch(accessor => { var localMetadata = accessor.GetFile(canonicalFilename, 0, 0).Metadata; var conflict = accessor.GetConfig(RavenFileNameHelper.ConflictConfigNameForFile(canonicalFilename)).JsonDeserialization<ConflictItem>(); ConflictResolver.ApplyRemoteStrategy(canonicalFilename, conflict, localMetadata); accessor.UpdateFileMetadata(canonicalFilename, localMetadata, null); // ConflictArtifactManager.Delete(canonicalFilename, accessor); - intentionally not deleting, conflict item will be removed when a remote file is put }); SynchronizationTask.Context.NotifyAboutWork(); break; default: throw new NotSupportedException(string.Format("{0} is not the valid strategy to resolve a conflict", strategy)); } return GetEmptyMessage(HttpStatusCode.NoContent); }
public override RemoteUploadResult UploadNoteToRemote(ref INote inote, out INote conflict, ConflictResolutionStrategy strategy) { var note = (StandardFileNote)inote; if (_syncResult.saved_notes.Any(n => n.ID == note.ID)) { note.ApplyUpdatedData(_syncResult.saved_notes.First(n => n.ID == note.ID)); conflict = null; return(RemoteUploadResult.Uploaded); } if (_syncResult.retrieved_notes.Any(n => n.ID == note.ID)) { _logger.Warn(StandardNotePlugin.Name, "Uploaded note found in retrieved notes ... upload failed ?"); note.ApplyUpdatedData(_syncResult.retrieved_notes.First(n => n.ID == note.ID)); conflict = null; return(RemoteUploadResult.Merged); } if (_syncResult.error_notes.Any(n => n.ID == note.ID)) { throw new Exception("Could not upload note - server returned note in {unsaved_notes}"); } if (_syncResult.conflict_notes.Any(n => n.ID == note.ID)) { conflict = _syncResult.conflict_notes.First(n => n.ID == note.ID); return(RemoteUploadResult.Conflict); } conflict = null; return(RemoteUploadResult.UpToDate); }
public long InsertWithOnConflict(String table, String nullColumnHack, ContentValues initialValues, ConflictResolutionStrategy conflictResolutionStrategy) { if (!String.IsNullOrWhiteSpace(nullColumnHack)) { var e = new InvalidOperationException("{0} does not support the 'nullColumnHack'.".Fmt(Tag)); Log.E(Tag, "Unsupported use of nullColumnHack", e); throw e; } var lastInsertedId = -1L; var command = GetInsertCommand(table, initialValues, conflictResolutionStrategy); try { int result; lock (dbLock) { result = command.step(); } if (result == SQLiteResult.ERROR) { throw new CouchbaseLiteException(raw.sqlite3_errmsg(db), StatusCode.DbError); } int changes; lock (dbLock) { changes = db.changes(); } if (changes > 0) { lock (dbLock) { lastInsertedId = db.last_insert_rowid(); } } if (lastInsertedId == -1L) { Log.E(Tag, "Error inserting " + initialValues + " using " + command); throw new CouchbaseLiteException("Error inserting " + initialValues + " using " + command, StatusCode.DbError); } else { Log.V(Tag, "Inserting row {0} into {1} with values {2}", lastInsertedId, table, initialValues); } } catch (Exception ex) { Log.E(Tag, "Error inserting into table " + table, ex); throw; } finally { lock (dbLock) { command.Dispose(); } } return(lastInsertedId); }
public long InsertWithOnConflict(String table, String nullColumnHack, ContentValues initialValues, ConflictResolutionStrategy conflictResolutionStrategy) { if (_readOnly) { throw Misc.CreateExceptionAndLog(Log.To.Database, StatusCode.Forbidden, TAG, "Attempting to write to a readonly database"); } if (!StringEx.IsNullOrWhiteSpace(nullColumnHack)) { throw new InvalidOperationException("Don't use nullColumnHack"); } Log.To.TaskScheduling.V(TAG, "Scheduling InsertWithOnConflict"); var t = Factory.StartNew(() => { Log.To.TaskScheduling.V(TAG, "Running InsertWithOnConflict"); var lastInsertedId = -1L; var command = GetInsertCommand(table, initialValues, conflictResolutionStrategy); try { LastErrorCode = command.step(); command.Dispose(); if (LastErrorCode == raw.SQLITE_ERROR) { throw Misc.CreateExceptionAndLog(Log.To.Database, StatusCode.DbError, TAG, raw.sqlite3_errmsg(_writeConnection)); } int changes = _writeConnection.changes(); if (changes > 0) { lastInsertedId = _writeConnection.last_insert_rowid(); } if (lastInsertedId == -1L) { if (conflictResolutionStrategy != ConflictResolutionStrategy.Ignore) { throw Misc.CreateExceptionAndLog(Log.To.Database, StatusCode.DbError, TAG, "Error inserting {0} using {1}", initialValues, command); } } else { Log.To.Database.V(TAG, "Inserting row {0} into {1} with values {2}", lastInsertedId, table, initialValues); } } catch (CouchbaseLiteException) { LastErrorCode = raw.sqlite3_errcode(_writeConnection); Log.To.Database.E(TAG, "Error inserting into table {0}, rethrowing...", table); throw; } catch (Exception ex) { LastErrorCode = raw.sqlite3_errcode(_writeConnection); throw Misc.CreateExceptionAndLog(Log.To.Database, ex, StatusCode.DbError, TAG, "Error inserting into table {0}", table); } return(lastInsertedId); }); var r = t.ConfigureAwait(false).GetAwaiter().GetResult(); if (t.Exception != null) { throw t.Exception; } return(r); }