Exemplo n.º 1
0
bool dlist_insert (DList* list, int32_t index, void* data) {
    assert(NULL != list);
    assert(0 <= index);
    assert(index <= list->count);

    if (0 == index) {
        return dlist_push_head(list, data);
    } else if (index == list->count) {
        return dlist_push_tail(list, data);
    } else if (index > list->count) {
        return false;
    }

    DListItem* item     = NULL;
    DListItem* new_item = (DListItem*) malloc(sizeof(DListItem));

    if (NULL == new_item) {
        return false;
    }

    __DLIST_GET(item, list, index);

    new_item->data       = data;
    new_item->next       = item;
    new_item->prev       = item->prev;
    new_item->next->prev = new_item;
    new_item->prev->next = new_item;
    list->count++;

    return true;
}
Exemplo n.º 2
0
bool dlist_push_tail_ts (DList* list, void* data) {
    assert(NULL != list);
    assert(NULL != list->mutex);

    pthread_mutex_lock(list->mutex);

    bool ret = dlist_push_tail(list, data);

    pthread_mutex_unlock(list->mutex);

    return ret;
}
Exemplo n.º 3
0
/*
 * pgstrom_program_cache_*
 *
 * a simple buddy memory allocation on the shared memory segment.
 */
static bool
pgstrom_program_cache_split(int shift)
{
	program_cache_entry *entry;
	dlist_node	   *dnode;

	Assert(shift > PGCACHE_MIN_BITS && shift <= PGCACHE_MAX_BITS);
	if (dlist_is_empty(&pgcache_head->free_list[shift]))
	{
		if (shift == PGCACHE_MAX_BITS ||
			!pgstrom_program_cache_split(shift + 1))
			return false;
	}
	Assert(!dlist_is_empty(&pgcache_head->free_list[shift]));

	dnode = dlist_pop_head_node(&pgcache_head->free_list[shift]);

	entry = dlist_container(program_cache_entry, hash_chain, dnode);
	Assert(entry->shift == shift);
	Assert((((uintptr_t)entry - (uintptr_t)pgcache_head->entry_begin)
			& ((1UL << shift) - 1)) == 0);
	shift--;

	/* earlier half */
	memset(entry, 0, offsetof(program_cache_entry, data[0]));
	entry->shift = shift;
	entry->refcnt = 0;
	PGCACHE_MAGIC_CODE(entry) = PGCACHE_MAGIC;
	dlist_push_tail(&pgcache_head->free_list[shift], &entry->hash_chain);

	/* later half */
	entry = (program_cache_entry *)((char *)entry + (1UL << shift));
	memset(entry, 0, offsetof(program_cache_entry, data[0]));
	entry->shift = shift;
	entry->refcnt = 0;
	PGCACHE_MAGIC_CODE(entry) = PGCACHE_MAGIC;
	dlist_push_tail(&pgcache_head->free_list[shift], &entry->hash_chain);

	return true;
}
Exemplo n.º 4
0
/*
 * StartPlacementListConnection returns a connection to a remote node suitable for
 * a placement accesses (SELECT, DML, DDL) or throws an error if no suitable
 * connection can be established if would cause a self-deadlock or consistency
 * violation.
 */
MultiConnection *
StartPlacementListConnection(uint32 flags, List *placementAccessList,
							 const char *userName)
{
	char *freeUserName = NULL;
	ListCell *placementAccessCell = NULL;
	List *placementEntryList = NIL;
	ListCell *placementEntryCell = NULL;
	MultiConnection *chosenConnection = NULL;

	if (userName == NULL)
	{
		userName = freeUserName = CurrentUserName();
	}

	chosenConnection = FindPlacementListConnection(flags, placementAccessList, userName,
												   &placementEntryList);
	if (chosenConnection == NULL)
	{
		/* use the first placement from the list to extract nodename and nodeport */
		ShardPlacementAccess *placementAccess =
			(ShardPlacementAccess *) linitial(placementAccessList);
		ShardPlacement *placement = placementAccess->placement;
		char *nodeName = placement->nodeName;
		int nodePort = placement->nodePort;

		/*
		 * No suitable connection in the placement->connection mapping, get one from
		 * the node->connection pool.
		 */
		chosenConnection = StartNodeUserDatabaseConnection(flags, nodeName, nodePort,
														   userName, NULL);

		if (flags & CONNECTION_PER_PLACEMENT &&
			ConnectionAccessedDifferentPlacement(chosenConnection, placement))
		{
			/*
			 * Cached connection accessed a non-co-located placement in the same
			 * table or co-location group, while the caller asked for a connection
			 * per placement. Open a new connection instead.
			 *
			 * We use this for situations in which we want to use a different
			 * connection for every placement, such as COPY. If we blindly returned
			 * a cached conection that already modified a different, non-co-located
			 * placement B in the same table or in a table with the same co-location
			 * ID as the current placement, then we'd no longer able to write to
			 * placement B later in the COPY.
			 */
			chosenConnection = StartNodeUserDatabaseConnection(flags |
															   FORCE_NEW_CONNECTION,
															   nodeName, nodePort,
															   userName, NULL);

			Assert(!ConnectionAccessedDifferentPlacement(chosenConnection, placement));
		}
	}

	/*
	 * Now that a connection has been chosen, initialise or update the connection
	 * references for all placements.
	 */
	forboth(placementAccessCell, placementAccessList,
			placementEntryCell, placementEntryList)
	{
		ShardPlacementAccess *placementAccess =
			(ShardPlacementAccess *) lfirst(placementAccessCell);
		ShardPlacementAccessType accessType = placementAccess->accessType;
		ConnectionPlacementHashEntry *placementEntry =
			(ConnectionPlacementHashEntry *) lfirst(placementEntryCell);
		ConnectionReference *placementConnection = placementEntry->primaryConnection;

		if (placementConnection->connection == chosenConnection)
		{
			/* using the connection that was already assigned to the placement */
		}
		else if (placementConnection->connection == NULL)
		{
			/* placement does not have a connection assigned yet */
			placementConnection->connection = chosenConnection;
			placementConnection->hadDDL = false;
			placementConnection->hadDML = false;
			placementConnection->userName = MemoryContextStrdup(TopTransactionContext,
																userName);
			placementConnection->placementId = placementAccess->placement->placementId;

			/* record association with connection */
			dlist_push_tail(&chosenConnection->referencedPlacements,
							&placementConnection->connectionNode);
		}
		else
		{
			/* using a different connection than the one assigned to the placement */

			if (accessType != PLACEMENT_ACCESS_SELECT)
			{
				/*
				 * We previously read from the placement, but now we're writing to
				 * it (if we had written to the placement, we would have either chosen
				 * the same connection, or errored out). Update the connection reference
				 * to point to the connection used for writing. We don't need to remember
				 * the existing connection since we won't be able to reuse it for
				 * accessing the placement. However, we do register that it exists in
				 * hasSecondaryConnections.
				 */
				placementConnection->connection = chosenConnection;
				placementConnection->userName = MemoryContextStrdup(TopTransactionContext,
																	userName);

				Assert(!placementConnection->hadDDL);
				Assert(!placementConnection->hadDML);

				/* record association with connection */
				dlist_push_tail(&chosenConnection->referencedPlacements,
								&placementConnection->connectionNode);
			}

			/*
			 * There are now multiple connections that read from the placement
			 * and DDL commands are forbidden.
			 */
			placementEntry->hasSecondaryConnections = true;

			if (placementEntry->colocatedEntry != NULL)
			{
				/* we also remember this for co-located placements */
				placementEntry->colocatedEntry->hasSecondaryConnections = true;
			}
		}

		/*
		 * Remember that we used the current connection for writes.
		 */
		if (accessType == PLACEMENT_ACCESS_DDL)
		{
			placementConnection->hadDDL = true;
		}

		if (accessType == PLACEMENT_ACCESS_DML)
		{
			placementConnection->hadDML = true;
		}
	}
Exemplo n.º 5
0
static
void
worker_thread_handle_msgqueue_event(
    struct worker_thread* state,
    uint32_t event_flags
    )
{
  if (event_flags & EPOLLERR) {
    D_FMTSTRING("Error on message queue!");
    return;
  }

  for (;;) {
    /*
     * Drain all the bytes from the queue descriptor.
     */
    struct message msg;
    ssize_t bytes = HANDLE_EINTR_ON_SYSCALL(
        mq_receive(state->wk_messagequeue.mq_queuefds,
                   (char*) &msg,
                   sizeof(msg),
                   NULL /* don't care about message priority */));
    if (bytes == -1) {
      if (errno == EAGAIN) {
        return;
      }
      D_FUNCFAIL_ERRNO(mq_receive);
      return;
    }
    BUGSTOP_IF((msg.msg_code != kITTMessageAddClient), 
               "Unknown message code");
    /*
     * The client object gets ownership of the socket descriptor.
     * Should anything go wrong in the creation process it will
     * close the socket descriptor.
     */
    struct client* clnt = client_create(msg.msg_data.msg_fd, 
                                        state->wk_allocator);
    if (!clnt) {
      /*
       * Client creation failed. Try to get next message, if any.
       * Close client socket.
       */
      HANDLE_EINTR_ON_SYSCALL(close(msg.msg_data.msg_fd));
      continue;
    }

    if (add_fd_to_epoll(state->wk_epoll_fds, clnt->cl_sockfd,
                        EPOLLIN | EPOLLRDHUP, kDataTypePTR,
                        clnt) == -1) {
      /*
       * Failed to add client socket to epoll so release all resources and get
       * the next message.
       */
      client_destroy(clnt, state->wk_allocator);
      continue;
    }
    /*
     * Add client to list.
     */
    dlist_push_tail(state->wk_clients, clnt); 
  }
}