static void cmp(const char* should_be, InfAdoptedStateVector* vec) {
  char* is;
  InfAdoptedStateVector* should_be_vec;
  
  is = inf_adopted_state_vector_to_string(vec);
  if (strcmp(should_be, is) != 0) {
    printf("should be: %s\n"
           "is:        %s\n"
           "strcmp failed\n", should_be, is);
    g_assert_not_reached();
  }

  should_be_vec = inf_adopted_state_vector_from_string(should_be, NULL);
  if (!should_be_vec
      || inf_adopted_state_vector_compare(vec, should_be_vec) != 0
      || inf_adopted_state_vector_compare(should_be_vec, vec) != 0) {
    printf("should be: %s\n"
           "is:        %s\n"
           "compare failed\n", should_be, is);
    g_assert_not_reached();
  }
  g_free(is);
  inf_adopted_state_vector_free(should_be_vec);
  printf("ok!\n");
}
Пример #2
0
/**
 * inf_adopted_request_need_concurrency_id:
 * @request: The request to transform.
 * @against: The request to transform against.
 *
 * Returns whether transforming @request against @against requires a
 * concurrency ID. You can still call inf_adopted_request_transform() with
 * a concurrency ID of %INF_ADOPTED_CONCURRENCY_NONE even if this function
 * returns %TRUE if you don't have another possibility to find a
 * concurrency ID in which case user IDs are used to determine which request
 * to transform.
 *
 * Both request need to be of type %INF_ADOPTED_REQUEST_DO, and their state
 * vectors must be the same.
 *
 * Returns: Whether transformation of @request against @against requires a
 * concurrency ID.
 */
gboolean
inf_adopted_request_need_concurrency_id(InfAdoptedRequest* request,
                                        InfAdoptedRequest* against)
{
    InfAdoptedRequestPrivate* request_priv;
    InfAdoptedRequestPrivate* against_priv;

    g_return_val_if_fail(INF_ADOPTED_IS_REQUEST(request), FALSE);
    g_return_val_if_fail(INF_ADOPTED_IS_REQUEST(against), FALSE);

    request_priv = INF_ADOPTED_REQUEST_PRIVATE(request);
    against_priv = INF_ADOPTED_REQUEST_PRIVATE(against);

    g_return_val_if_fail(request_priv->type == INF_ADOPTED_REQUEST_DO, FALSE);
    g_return_val_if_fail(against_priv->type == INF_ADOPTED_REQUEST_DO, FALSE);
    g_return_val_if_fail(request_priv->user_id != against_priv->user_id, FALSE);

    g_return_val_if_fail(
        inf_adopted_state_vector_compare(
            request_priv->vector,
            against_priv->vector
        ) == 0,
        FALSE
    );

    return inf_adopted_operation_need_concurrency_id(
               request_priv->operation,
               against_priv->operation
           );
}
Пример #3
0
/**
 * inf_adopted_request_get_concurrency_id:
 * @request: The request to transform.
 * @against: The request to transform against.
 *
 * Returns a concurrency ID for transformation of @operation against @against.
 * It always returns %INF_ADOPTED_CONCURRENCY_NONE when
 * inf_adopted_request_need_concurrency_id() returns %TRUE (but that's not
 * necessarily true the other way around), since it is not possible to decide
 * which operation to transform without any additional information.
 *
 * However, the function can be called on the same requests in a previous
 * state. In some cases, a decision can be made based on these previous
 * requests. This can be used as a concurrency ID for a call to
 * inf_adopted_request_transform(). If this does not yield a decision, it is
 * still possible to call inf_adopted_request_transform() with
 * %INF_ADOPTED_CONCURRENCY_NONE as concurrency ID in which case an arbitrary
 * request will be transformed, based on the user IDs of the requests.
 *
 * Both requests must be of type %INF_ADOPTED_REQUEST_DO, and their state
 * vectors must be the same.
 *
 * Returns: A concurrency ID between @operation and @against. Can be
 * %INF_ADOPTED_CONCURRENCY_NONE in case no decision can be made.
 */
InfAdoptedConcurrencyId
inf_adopted_request_get_concurrency_id(InfAdoptedRequest* request,
                                       InfAdoptedRequest* against)
{
    InfAdoptedRequestPrivate* request_priv;
    InfAdoptedRequestPrivate* against_priv;

    g_return_val_if_fail(
        INF_ADOPTED_IS_REQUEST(request),
        INF_ADOPTED_CONCURRENCY_NONE
    );
    g_return_val_if_fail(
        INF_ADOPTED_IS_REQUEST(against),
        INF_ADOPTED_CONCURRENCY_NONE
    );

    request_priv = INF_ADOPTED_REQUEST_PRIVATE(request);
    against_priv = INF_ADOPTED_REQUEST_PRIVATE(against);

    g_return_val_if_fail(
        request_priv->type == INF_ADOPTED_REQUEST_DO,
        INF_ADOPTED_CONCURRENCY_NONE
    );
    g_return_val_if_fail(
        against_priv->type == INF_ADOPTED_REQUEST_DO,
        INF_ADOPTED_CONCURRENCY_NONE
    );
    g_return_val_if_fail(
        request_priv->user_id != against_priv->user_id,
        INF_ADOPTED_CONCURRENCY_NONE
    );

    g_return_val_if_fail(
        inf_adopted_state_vector_compare(
            request_priv->vector,
            against_priv->vector
        ) == 0,
        INF_ADOPTED_CONCURRENCY_NONE
    );

    return inf_adopted_operation_get_concurrency_id(
               request_priv->operation,
               against_priv->operation
           );
}
Пример #4
0
static void
inf_adopted_session_local_user_added(InfAdoptedSession* session,
                                     InfAdoptedUser* user)
{
  InfAdoptedSessionPrivate* priv;
  InfSessionStatus status;
  InfAdoptedSessionLocalUser* local;
  InfAdoptedStateVector* current_state;

  priv = INF_ADOPTED_SESSION_PRIVATE(session);
  status = inf_session_get_status(INF_SESSION(session));

  /* Cannot be local while synchronizing */
  g_assert(status == INF_SESSION_RUNNING);

  local = g_slice_new(InfAdoptedSessionLocalUser);
  local->user = user;

  local->last_send_vector = inf_adopted_state_vector_copy(
    inf_adopted_user_get_vector(user)
  );

  /* Set current vector for local user, this is kept up-to-date by
   * InfAdoptedAlgorithm. TODO: Also do this in InfAdoptedAlgorithm? */
  inf_adopted_user_set_vector(
    user,
    inf_adopted_state_vector_copy(
      inf_adopted_algorithm_get_current(priv->algorithm)
    )
  );

  local->noop_time = 0;

  priv->local_users = g_slist_prepend(priv->local_users, local);

  /* Start noop timer if user is not up to date */
  current_state = inf_adopted_algorithm_get_current(priv->algorithm);
  if(inf_adopted_state_vector_compare(current_state, local->last_send_vector))
    inf_adopted_session_start_noop_timer(session, local);
}
Пример #5
0
/**
 * inf_adopted_request_transform:
 * @request: The request to transform.
 * @against: The request to transform against.
 * @concurrency_id: A concurrency ID for the transformation.
 *
 * Transforms the operation of @request against the operation of @against.
 * Both requests must be of type %INF_ADOPTED_REQUEST_DO, and their state
 * vectors must be the same.
 *
 * @concurrency_id can be %INF_ADOPTED_CONCURRENCY_NONE even if the
 * transformation requires a concurrency ID (see
 * inf_adopted_request_need_concurrency_id()). In that case, it is assumed
 * that it does not matter which operation to transform, and user IDs are
 * used to determine a concurrency ID for the transformation.
 *
 * Returns: A new #InfAdoptedRequest, the result of the transformation.
 **/
InfAdoptedRequest*
inf_adopted_request_transform(InfAdoptedRequest* request,
                              InfAdoptedRequest* against,
                              InfAdoptedConcurrencyId concurrency_id)
{
    InfAdoptedRequestPrivate* request_priv;
    InfAdoptedRequestPrivate* against_priv;
    InfAdoptedOperation* new_operation;
    InfAdoptedStateVector* new_vector;
    InfAdoptedRequest* new_request;

    g_return_val_if_fail(INF_ADOPTED_IS_REQUEST(request), NULL);
    g_return_val_if_fail(INF_ADOPTED_IS_REQUEST(against), NULL);

    request_priv = INF_ADOPTED_REQUEST_PRIVATE(request);
    against_priv = INF_ADOPTED_REQUEST_PRIVATE(against);

    g_return_val_if_fail(request_priv->type == INF_ADOPTED_REQUEST_DO, NULL);
    g_return_val_if_fail(against_priv->type == INF_ADOPTED_REQUEST_DO, NULL);
    g_return_val_if_fail(request_priv->user_id != against_priv->user_id, NULL);

    g_return_val_if_fail(
        inf_adopted_state_vector_compare(
            request_priv->vector,
            against_priv->vector
        ) == 0, NULL
    );

    if(concurrency_id != INF_ADOPTED_CONCURRENCY_NONE)
    {
        new_operation = inf_adopted_operation_transform(
                            request_priv->operation,
                            against_priv->operation,
                            concurrency_id
                        );
    }
    else if(request_priv->user_id > against_priv->user_id)
    {
        new_operation = inf_adopted_operation_transform(
                            request_priv->operation,
                            against_priv->operation,
                            INF_ADOPTED_CONCURRENCY_OTHER
                        );
    }
    else
    {
        new_operation = inf_adopted_operation_transform(
                            request_priv->operation,
                            against_priv->operation,
                            INF_ADOPTED_CONCURRENCY_SELF
                        );
    }

    new_vector = inf_adopted_state_vector_copy(request_priv->vector);
    inf_adopted_state_vector_add(new_vector, against_priv->user_id, 1);

    new_request = inf_adopted_request_new_do(
                      new_vector,
                      request_priv->user_id,
                      new_operation
                  );

    g_object_unref(new_operation);
    inf_adopted_state_vector_free(new_vector);
    return new_request;
}