Skip to content
This repository has been archived by the owner on Feb 29, 2020. It is now read-only.

Commit

Permalink
[client][managed][offline] added force option to purge data and pendi…
Browse files Browse the repository at this point in the history
…ng operations on data
  • Loading branch information
hasankhan committed Nov 18, 2014
1 parent ca04a3b commit aa51d9f
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -121,29 +120,40 @@ public static Task PullAsync<T, U>(this IMobileServiceSyncTable<T> table, string
/// <summary>
/// Deletes all the items in local table
/// </summary>
/// <param name="table">The instance of table to execute pull on.</param>
/// <param name="table">The instance of table to execute purge on.</param>
/// <returns>A task that completes when purge operation has finished.</returns>
public static Task PurgeAsync(this IMobileServiceSyncTable table)
{
return table.PurgeAsync(String.Empty);
return table.PurgeAsync(null, null, false, CancellationToken.None);
}

/// <summary>
/// Deletes all the items in local table
/// </summary>
/// <param name="table">The instance of table to execute purge on.</param>
/// <param name="force">Force the purge by discarding the pending operations.</param>
/// <returns>A task that completes when purge operation has finished.</returns>
public static Task PurgeAsync(this IMobileServiceSyncTable table, bool force)
{
return table.PurgeAsync(null, null, force, CancellationToken.None);
}

/// <summary>
/// Deletes all the items in local table that match the query.
/// </summary>
/// <param name="table">The instance of table to execute pull on.</param>
/// <param name="table">The instance of table to execute purge on.</param>
/// <param name="query">An OData query that determines which items to delete.</param>
/// <returns>A task that completes when purge operation has finished.</returns>
public static Task PurgeAsync(this IMobileServiceSyncTable table, string query)
{
return table.PurgeAsync(null, query, CancellationToken.None);
return table.PurgeAsync(null, query, false, CancellationToken.None);
}


/// <summary>
/// Deletes all the items in local table that match the query.
/// </summary>
/// <param name="table">The instance of table to execute pull on.</param>
/// <param name="table">The instance of table to execute purge on.</param>
/// <param name="query">An OData query that determines which items to delete.</param>
/// <returns>A task that completes when purge operation has finished.</returns>
public static Task PurgeAsync<T, U>(this IMobileServiceSyncTable<T> table, IMobileServiceTableQuery<U> query)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,10 @@ public interface IMobileServiceSyncTable
/// A string that uniquely identifies this query and is used to keep track of its sync state. Supplying this parameter resets the incremental sync state for the query.
/// </param>
/// <param name="query">An OData query that determines which items to delete.</param>
/// <param name="force">Force the purge by discarding the pending operations.</param>
/// <param name="cancellationToken">The <see cref="System.Threading.CancellationToken"/> token to observe
/// </param>
/// <returns>A task that completes when purge operation has finished.</returns>
Task PurgeAsync(string queryId, string query, CancellationToken cancellationToken);
Task PurgeAsync(string queryId, string query, bool force, CancellationToken cancellationToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -237,13 +237,13 @@ public async Task PullAsync(string tableName, MobileServiceTableKind tableKind,
await this.ExecuteSyncAction(action);
}

public async Task PurgeAsync(string tableName, MobileServiceTableKind tableKind, string queryId, string query, CancellationToken cancellationToken)
public async Task PurgeAsync(string tableName, MobileServiceTableKind tableKind, string queryId, string query, bool force, CancellationToken cancellationToken)
{
await this.EnsureInitializedAsync();

var table = await this.GetTable(tableName);
var queryDescription = MobileServiceTableQueryDescription.Parse(tableName, query);
var action = new PurgeAction(table, tableKind, queryId, queryDescription, this, this.opQueue, this.settings, this.Store, cancellationToken);
var action = new PurgeAction(table, tableKind, queryId, queryDescription, force, this, this.opQueue, this.settings, this.Store, cancellationToken);
await this.ExecuteSyncAction(action);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ private async Task<string> GetSettingAsync(string key, string defaultValue)

private string GetDeltaTokenKey(string tableName, string queryId)
{
return tableName + "_" + queryId + "_deltaToken";
return tableName + "_deltaToken_" + queryId;
}

private static string GetSystemPropertiesKey(string tableName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public Task PurgeAsync<U>(string queryId, IMobileServiceTableQuery<U> query, Can
}
string queryString = this.queryProvider.ToODataString(query);

return this.PurgeAsync(queryId, queryString, cancellationToken);
return this.PurgeAsync(queryId, queryString, false, cancellationToken);
}

public async Task RefreshAsync(T instance)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ public Task PullAsync(string queryId, string query, IDictionary<string, string>
return this.syncContext.PullAsync(this.TableName, this.Kind, queryId, query, this.SupportedOptions, parameters, pushOtherTables ? new string[0] : null, null, cancellationToken);
}

public Task PurgeAsync(string queryId, string query, CancellationToken cancellationToken)
public Task PurgeAsync(string queryId, string query, bool force, CancellationToken cancellationToken)
{
ValidateQueryId(queryId);
return this.syncContext.PurgeAsync(this.TableName, this.Kind, queryId, query, cancellationToken);
return this.syncContext.PurgeAsync(this.TableName, this.Kind, queryId, query, force, cancellationToken);
}

public async Task<JObject> InsertAsync(JObject instance)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ internal class PullAction : TableAction
private IDictionary<string, string> parameters;
private MobileServiceRemoteTableOptions options; // the supported options on remote table
private readonly PullCursor cursor;
private Task pendingAction;
private PullStrategy strategy;

public PullAction(MobileServiceTable table,
Expand All @@ -44,9 +45,18 @@ public PullAction(MobileServiceTable table,

public MobileServiceObjectReader Reader { get; private set; }

protected override bool CanDeferIfDirty

protected override Task<bool> HandleDirtyTable()
{
// there are pending operations on the same table so defer the action
this.pendingAction = this.Context.DeferTableActionAsync(this);
// we need to return in order to give PushAsync a chance to execute so we don't await the pending push
return Task.FromResult(false);
}

protected override Task WaitPendingAction()
{
get { return true; }
return this.pendingAction ?? Task.FromResult(0);
}

protected async override Task ProcessTableAsync()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,51 @@ namespace Microsoft.WindowsAzure.MobileServices.Sync
{
internal class PurgeAction : TableAction
{
private bool force;

public PurgeAction(MobileServiceTable table,
MobileServiceTableKind tableKind,
string queryId,
MobileServiceTableQueryDescription query,
bool force,
MobileServiceSyncContext context,
OperationQueue operationQueue,
MobileServiceSyncSettingsManager settings,
IMobileServiceLocalStore store,
CancellationToken cancellationToken)
: base(table, tableKind, queryId, query, null, context, operationQueue, settings, store, cancellationToken)
{
this.force = force;
}

protected override bool CanDeferIfDirty
protected async override Task<bool> HandleDirtyTable()
{
get { return false; }
if (this.Query.Filter != null || !this.force)
{
throw new InvalidOperationException(Resources.SyncContext_PurgeOnDirtyTable);
}

var delOperationsQuery = new MobileServiceTableQueryDescription(MobileServiceLocalSystemTables.OperationQueue);
delOperationsQuery.Filter = new BinaryOperatorNode(BinaryOperatorKind.Equal, new MemberAccessNode(null, "tableName"), new ConstantNode(this.Table.TableName));

// count ops to be deleted
delOperationsQuery.IncludeTotalCount = true;
delOperationsQuery.Top = 0;
long toRemove = QueryResult.Parse(await this.Store.ReadAsync(delOperationsQuery), null, validate: false).TotalCount;

// delete operations
delOperationsQuery.Top = null;
await this.Store.DeleteAsync(delOperationsQuery);

// delete errors
var delErrorsQuery = new MobileServiceTableQueryDescription(MobileServiceLocalSystemTables.SyncErrors);
delErrorsQuery.Filter = delOperationsQuery.Filter;
await this.Store.DeleteAsync(delErrorsQuery);

// update queue operation count
this.OperationQueue.UpdateOperationCount(-toRemove);

return true;
}

protected override async Task ProcessTableAsync()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ namespace Microsoft.WindowsAzure.MobileServices.Sync
/// </summary>
internal abstract class TableAction : SyncAction
{
private Task pendingPush;
private MobileServiceSyncContext context;
protected MobileServiceSyncContext Context { get; private set; }

protected string QueryId { get; private set; }
protected MobileServiceTableQueryDescription Query { get; private set; }
Expand All @@ -25,7 +24,6 @@ internal abstract class TableAction : SyncAction

protected MobileServiceSyncSettingsManager Settings { get; private set; }

protected abstract bool CanDeferIfDirty { get; }
public IEnumerable<string> RelatedTables { get; set; }

public TableAction(MobileServiceTable table,
Expand All @@ -46,30 +44,20 @@ public TableAction(MobileServiceTable table,
this.Query = query;
this.RelatedTables = relatedTables;
this.Settings = settings;
this.context = context;
this.Context = context;
}

public async override Task ExecuteAsync()
{
try
{
if (this.pendingPush != null)
{
await pendingPush; // this will cause any failed push to fail this dependant table action also
}
await this.WaitPendingAction();

using (await this.OperationQueue.LockTableAsync(this.Table.TableName, this.CancellationToken))
{
if (await this.OperationQueue.CountPending(this.Table.TableName) > 0)
if (await this.OperationQueue.CountPending(this.Table.TableName) > 0 && !await this.HandleDirtyTable())
{
if (this.CanDeferIfDirty)
{
// there are pending operations on the same table so defer the action
this.pendingPush = this.context.DeferTableActionAsync(this);
// we need to return in order to give PushAsync a chance to execute so we don't await the pending push
return;
}
throw new InvalidOperationException(Resources.SyncContext_PurgeOnDirtyTable);
return; // table is dirty and we cannot proceed for execution as handle return false
}

await this.ProcessTableAsync();
Expand All @@ -83,6 +71,13 @@ public async override Task ExecuteAsync()
this.TaskSource.SetResult(0);
}

protected virtual Task WaitPendingAction()
{
return Task.FromResult(0);
}

protected abstract Task<bool> HandleDirtyTable();

protected abstract Task ProcessTableAsync();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,17 @@ public long PendingOperations
get { return pendingOperations; }
}

internal void UpdateOperationCount(long delta)
{
long current, updated;
do
{
current = this.pendingOperations;
updated = current + delta;
}
while (current != Interlocked.CompareExchange(ref this.pendingOperations, updated, current));
}

public virtual async Task<long> CountPending(string tableName)
{
MobileServiceTableQueryDescription query = CreateQuery();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public Task<JToken> ReadAsync(MobileServiceTableQueryDescription query)
public Task DeleteAsync(MobileServiceTableQueryDescription query)
{
this.DeleteQueries.Add(query);
this.TableMap[query.TableName].Clear();
GetTable(query.TableName).Clear();
return Task.FromResult(0);
}

Expand Down
Loading

0 comments on commit aa51d9f

Please sign in to comment.