@Override
    public void run() {
      if (recordUploadFailed) {
        Logger.info(
            LOG_TAG, "Previous record upload failed.  Failing all records and not retrying.");
        Exception ex = new Server11PreviousPostFailedException();
        for (String guid : outgoingGuids) {
          delegate.onRecordStoreFailed(ex, guid);
        }
        return;
      }

      if (outgoing == null || outgoing.size() == 0) {
        Logger.debug(LOG_TAG, "No items: RecordUploadRunnable returning immediately.");
        return;
      }

      URI u = serverRepository.collectionURI();
      SyncStorageRequest request = new SyncStorageRequest(u);

      request.delegate = this;

      // We don't want the task queue to proceed until this request completes.
      // Fortunately, BaseResource is currently synchronous.
      // If that ever changes, you'll need to block here.
      ByteArraysEntity body = getBodyEntity();
      request.post(body);
    }
 @Override
 public void stored() {
   Logger.debug(LOG_TAG, "Record stored. Notifying.");
   synchronized (storeSerializer) {
     Logger.debug(LOG_TAG, "stored() took storeSerializer.");
     counter++;
     storeSerializer.notify();
     Logger.debug(LOG_TAG, "stored() dropped storeSerializer.");
   }
 }
Example #3
0
  public void performNotify(final Throwable e) {
    if (e != null) {
      Logger.debug(LOG_TAG, "performNotify called with Throwable: " + e.getMessage());
    } else {
      Logger.debug(LOG_TAG, "performNotify called.");
    }

    if (!queue.offer(new Result(e))) {
      // This could happen if performNotify is called multiple times (which is an error).
      throw new MultipleNotificationsError();
    }
  }
 /**
  * Return the X-Weave-Timestamp header from <code>response</code>, or the current time if it is
  * missing.
  *
  * <p><b>Warning:</b> this can cause the timestamp of <code>response</code> to cross domains (from
  * server clock to local clock), which could cause records to be skipped on account of clock
  * drift. This should never happen, because <i>every</i> server response should have a well-formed
  * X-Weave-Timestamp header.
  *
  * @param response The <code>SyncStorageResponse</code> to interrogate.
  * @return Normalized timestamp in milliseconds.
  */
 public static long getNormalizedTimestamp(SyncStorageResponse response) {
   long normalizedTimestamp = -1;
   try {
     normalizedTimestamp = response.normalizedWeaveTimestamp();
   } catch (NumberFormatException e) {
     Logger.warn(LOG_TAG, "Malformed X-Weave-Timestamp header received.", e);
   }
   if (-1 == normalizedTimestamp) {
     Logger.warn(
         LOG_TAG,
         "Computing stand-in timestamp from local clock. Clock drift could cause records to be skipped.");
     normalizedTimestamp = System.currentTimeMillis();
   }
   return normalizedTimestamp;
 }
 @Override
 public void queueFilled() {
   Logger.debug(LOG_TAG, "Queue filled.");
   synchronized (monitor) {
     this.stopEventually = true;
     monitor.notify();
   }
 }
 @Override
 public void halt() {
   Logger.debug(LOG_TAG, "Halting.");
   synchronized (monitor) {
     this.stopEventually = true;
     this.stopImmediately = true;
     monitor.notify();
   }
 }
 private void consumerIsDone() {
   long counterNow = this.counter;
   Logger.info(
       LOG_TAG,
       "Consumer is done. Processed "
           + counterNow
           + ((counterNow == 1) ? " record." : " records."));
   delegate.consumerIsDone(stopImmediately);
 }
    @Override
    public void handleRequestSuccess(SyncStorageResponse response) {
      Logger.debug(LOG_TAG, "Fetch done.");
      removeRequestFromPending();

      final long normalizedTimestamp = getNormalizedTimestamp(response);
      Logger.debug(LOG_TAG, "Fetch completed. Timestamp is " + normalizedTimestamp);

      // When we're done processing other events, finish.
      workTracker.delayWorkItem(
          new Runnable() {
            @Override
            public void run() {
              Logger.debug(LOG_TAG, "Delayed onFetchCompleted running.");
              // TODO: verify number of returned records.
              delegate.onFetchCompleted(normalizedTimestamp);
            }
          });
    }
 @Override
 protected boolean isEnabled() throws MetaGlobalException {
   if (session == null || session.getContext() == null) {
     return false;
   }
   boolean migrated = FennecControlHelper.isHistoryMigrated(session.getContext());
   if (!migrated) {
     Logger.warn(LOG_TAG, "Not enabling history engine since Fennec history is not migrated.");
   }
   return super.isEnabled() && migrated;
 }
    @Override
    public void handleRequestError(final Exception ex) {
      Logger.warn(LOG_TAG, "Got request error.", ex);

      recordUploadFailed = true;
      ArrayList<String> failedOutgoingGuids = outgoingGuids;
      outgoingGuids = null; // Want to GC this ASAP.
      for (String guid : failedOutgoingGuids) {
        delegate.onRecordStoreFailed(ex, guid);
      }
      return;
    }
 public RecordUploadRunnable(
     RepositorySessionStoreDelegate storeDelegate,
     ArrayList<byte[]> outgoing,
     ArrayList<String> outgoingGuids,
     long byteCount) {
   Logger.debug(
       LOG_TAG,
       "Preparing record upload for " + outgoing.size() + " records (" + byteCount + " bytes).");
   this.outgoing = outgoing;
   this.outgoingGuids = outgoingGuids;
   this.byteCount = byteCount;
 }
 @Override
 public void handleWBO(CryptoRecord record) {
   workTracker.incrementOutstanding();
   try {
     delegate.onFetchedRecord(record);
   } catch (Exception ex) {
     Logger.warn(LOG_TAG, "Got exception calling onFetchedRecord with WBO.", ex);
     // TODO: handle this better.
     throw new RuntimeException(ex);
   } finally {
     workTracker.decrementOutstanding();
   }
 }
 @Override
 public void handleRequestError(final Exception ex) {
   removeRequestFromPending();
   Logger.warn(LOG_TAG, "Got request error.", ex);
   // When we're done processing other events, finish.
   workTracker.delayWorkItem(
       new Runnable() {
         @Override
         public void run() {
           Logger.debug(LOG_TAG, "Running onFetchFailed.");
           delegate.onFetchFailed(ex, null);
         }
       });
 }
 @Override
 public void storeDone() {
   Logger.debug(LOG_TAG, "storeDone().");
   synchronized (recordsBufferMonitor) {
     flush();
     // Do this in a Runnable so that the timestamp is grabbed after any upload.
     final Runnable r =
         new Runnable() {
           @Override
           public void run() {
             synchronized (recordsBufferMonitor) {
               final long end = uploadTimestamp.get();
               Logger.debug(LOG_TAG, "Calling storeDone with " + end);
               storeDone(end);
             }
           }
         };
     storeWorkQueue.execute(r);
   }
 }
Example #15
0
  public void performWait(int waitTimeoutInMillis, Runnable action) throws WaitHelperError {
    Logger.debug(LOG_TAG, "performWait called.");

    Result result = null;

    try {
      if (action != null) {
        try {
          action.run();
          Logger.debug(LOG_TAG, "Action done.");
        } catch (Exception ex) {
          Logger.debug(LOG_TAG, "Performing action threw: " + ex.getMessage());
          throw new InnerError(ex);
        }
      }

      if (waitTimeoutInMillis < 0) {
        result = queue.take();
      } else {
        result = queue.poll(waitTimeoutInMillis, TimeUnit.MILLISECONDS);
      }
      Logger.debug(LOG_TAG, "Got result from queue: " + result);
    } catch (InterruptedException e) {
      // We were interrupted.
      Logger.debug(LOG_TAG, "performNotify interrupted with InterruptedException " + e);
      final InterruptedError interruptedError = new InterruptedError();
      interruptedError.initCause(e);
      throw interruptedError;
    }

    if (result == null) {
      // We timed out.
      throw new TimeoutError(waitTimeoutInMillis);
    } else if (result.error != null) {
      Logger.debug(LOG_TAG, "Notified with error: " + result.error.getMessage());

      // Rethrow any assertion with which we were notified.
      InnerError innerError = new InnerError(result.error);
      throw innerError;
    }
    // Success!
  }
 private void storeSerially(Record record) {
   Logger.debug(LOG_TAG, "New record to store.");
   synchronized (storeSerializer) {
     Logger.debug(LOG_TAG, "storeSerially() took storeSerializer.");
     Logger.debug(LOG_TAG, "Storing...");
     try {
       this.delegate.store(record);
     } catch (Exception e) {
       Logger.warn(LOG_TAG, "Got exception in store. Not waiting.", e);
       return; // So we don't block for a stored() that never comes.
     }
     try {
       Logger.debug(LOG_TAG, "Waiting...");
       storeSerializer.wait();
     } catch (InterruptedException e) {
       // TODO
     }
     Logger.debug(LOG_TAG, "storeSerially() dropped storeSerializer.");
   }
 }
  @Override
  public void run() {
    while (true) {
      synchronized (monitor) {
        Logger.debug(LOG_TAG, "run() took monitor.");
        if (stopImmediately) {
          Logger.debug(LOG_TAG, "Stopping immediately. Clearing queue.");
          delegate.getQueue().clear();
          Logger.debug(LOG_TAG, "Notifying consumer.");
          consumerIsDone();
          return;
        }
        Logger.debug(LOG_TAG, "run() dropped monitor.");
      }
      // The queue is concurrent-safe.
      while (!delegate.getQueue().isEmpty()) {
        Logger.debug(LOG_TAG, "Grabbing record...");
        Record record = delegate.getQueue().remove();
        // Block here, allowing us to process records
        // serially.
        Logger.debug(LOG_TAG, "Invoking storeSerially...");
        this.storeSerially(record);
        Logger.debug(LOG_TAG, "Done with record.");
      }
      synchronized (monitor) {
        Logger.debug(LOG_TAG, "run() took monitor.");

        if (stopEventually) {
          Logger.debug(LOG_TAG, "Done with records and told to stop. Notifying consumer.");
          consumerIsDone();
          return;
        }
        try {
          Logger.debug(LOG_TAG, "Not told to stop but no records. Waiting.");
          monitor.wait(10000);
        } catch (InterruptedException e) {
          // TODO
        }
        Logger.debug(LOG_TAG, "run() dropped monitor.");
      }
    }
  }
    @Override
    public void handleRequestSuccess(SyncStorageResponse response) {
      Logger.trace(LOG_TAG, "POST of " + outgoing.size() + " records done.");

      ExtendedJSONObject body;
      try {
        body = response.jsonObjectBody(); // jsonObjectBody() throws or returns non-null.
      } catch (Exception e) {
        Logger.error(LOG_TAG, "Got exception parsing POST success body.", e);
        this.handleRequestError(e);
        return;
      }

      // Be defensive when logging timestamp.
      if (body.containsKey("modified")) {
        Long modified = body.getTimestamp("modified");
        if (modified != null) {
          Logger.trace(
              LOG_TAG, "POST request success. Modified timestamp: " + modified.longValue());
        } else {
          Logger.warn(
              LOG_TAG, "POST success body contains malformed 'modified': " + body.toJSONString());
        }
      } else {
        Logger.warn(
            LOG_TAG, "POST success body does not contain key 'modified': " + body.toJSONString());
      }

      try {
        JSONArray success = body.getArray("success");
        if ((success != null) && (success.size() > 0)) {
          Logger.trace(LOG_TAG, "Successful records: " + success.toString());
          for (Object o : success) {
            try {
              delegate.onRecordStoreSucceeded((String) o);
            } catch (ClassCastException e) {
              Logger.error(LOG_TAG, "Got exception parsing POST success guid.", e);
              // Not much to be done.
            }
          }

          long normalizedTimestamp = getNormalizedTimestamp(response);
          Logger.trace(LOG_TAG, "Passing back upload X-Weave-Timestamp: " + normalizedTimestamp);
          bumpUploadTimestamp(normalizedTimestamp);
        }
        success = null; // Want to GC this ASAP.

        ExtendedJSONObject failed = body.getObject("failed");
        if ((failed != null) && (failed.object.size() > 0)) {
          Logger.debug(LOG_TAG, "Failed records: " + failed.object.toString());
          Exception ex = new Server11RecordPostFailedException();
          for (String guid : failed.keySet()) {
            delegate.onRecordStoreFailed(ex, guid);
          }
        }
        failed = null; // Want to GC this ASAP.
      } catch (UnexpectedJSONException e) {
        Logger.error(LOG_TAG, "Got exception processing success/failed in POST success body.", e);
        // TODO
        return;
      }
      Logger.debug(LOG_TAG, "POST of " + outgoing.size() + " records handled.");
    }