[ 
https://issues.apache.org/jira/browse/TS-4723?focusedWorklogId=26924&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-26924
 ]

ASF GitHub Bot logged work on TS-4723:
--------------------------------------

                Author: ASF GitHub Bot
            Created on: 23/Aug/16 14:36
            Start Date: 23/Aug/16 14:36
    Worklog Time Spent: 10m 
      Work Description: Github user SolidWallOfCode commented on a diff in the 
pull request:

    https://github.com/apache/trafficserver/pull/843#discussion_r75879116
  
    --- Diff: plugins/experimental/carp/HttpFetch.cc ---
    @@ -0,0 +1,439 @@
    +/** @file
    +
    +  Limited URL fetcher..
    +
    +  @section license License
    +
    +  Licensed to the Apache Software Foundation (ASF) under one
    +  or more contributor license agreements.  See the NOTICE file
    +  distributed with this work for additional information
    +  regarding copyright ownership.  The ASF licenses this file
    +  to you under the Apache License, Version 2.0 (the
    +  "License"); you may not use this file except in compliance
    +  with the License.  You may obtain a copy of the License at
    +
    +      http://www.apache.org/licenses/LICENSE-2.0
    +
    +  Unless required by applicable law or agreed to in writing, software
    +  distributed under the License is distributed on an "AS IS" BASIS,
    +  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +  See the License for the specific language governing permissions and
    +  limitations under the License.
    + */
    +
    +#define __STDC_LIMIT_MACROS   // need INT64_MAX definition
    +#include <stdint.h>
    +#include <sys/time.h>
    +
    +#include "HttpFetch.h"
    +#include "UrlComponents.h"
    +#include "Common.h"
    +
    +using std::string;
    +
    +/**********************************************************/
    +// just 'pass through' and call object's handlEvent fn
    +
    +static int
    +handleHttpFetchIOEvents(TSCont cont, TSEvent event, void *edata)
    +{
    +  HttpFetch *fetchObj = static_cast<HttpFetch *> (TSContDataGet(cont));
    +  if (NULL == fetchObj) {
    +    TSDebug(DEBUG_FETCH_TAG, "handleHttpFetchEvents continuation data 
NULL");
    +    TSAssert(fetchObj);
    +  }
    +  return fetchObj->handleIOEvent(cont, event, edata);
    +}
    +
    +/**********************************************************/
    +HttpFetch::HttpFetch(const std::string &url, HashAlgorithm *hashAlgo,
    +    HashNode *hashNode,const char *method)
    +{
    +  TSMBuffer bufp;
    +  _url = url;
    +  _respInfo = NULL;
    +  _reqInfo  = NULL;
    +  _hashAlgo = hashAlgo;
    +  _hashNode = hashNode;
    +  _hcTimeoutSecond = DEFAULT_HEALTH_CHECK_TIMEOUT;
    +
    +  bufp = TSMBufferCreate();
    +
    +  if (bufp != NULL) {
    +    TSMLoc urlp;
    +    if (TSUrlCreate(bufp, &urlp) == TS_SUCCESS) {
    +      const char *start = url.data();
    +      if (TSUrlParse(bufp, urlp, &start, start + url.length()) == 
TS_PARSE_DONE) {
    +        UrlComponents reqUrl;
    +        string sPath;
    +        string sHost;
    +        reqUrl.populate(bufp, urlp);
    +        reqUrl.getCompletePathString(sPath);
    +        reqUrl.getCompleteHostString(sHost);
    +        _request = string(method) + " " + sPath + " HTTP/1.0\r\nHost: " + 
sHost + "\r\n";
    +        _request += CARP_ROUTED_HEADER + ": 1\r\n";
    +        _request += "\r\n";
    +      }
    +      TSHandleMLocRelease(bufp, NULL, urlp);
    +    }
    +  }
    +  TSMBufferDestroy(bufp);
    +  TSDebug(DEBUG_FETCH_TAG, "HttpFetch assembled this request %s", 
_request.c_str());
    +  _responseStatus=TS_HTTP_STATUS_NONE;
    +  _ready = true;
    +}
    +
    +/**********************************************************/
    +HttpFetch::~HttpFetch()
    +{
    +}
    +/**********************************************************/
    +void
    +HttpFetch::setHealthcheckTimeout(int timeout) {
    +  _hcTimeoutSecond = timeout;
    +}
    +/**********************************************************/
    +void
    +HttpFetch::makeAsyncRequest(struct sockaddr const* serverAddr)
    +{
    +  _ready = false;
    +  __sync_synchronize();
    +  _result = UNKNOWN;
    +  TSCont fetchCont = TSContCreate(handleHttpFetchIOEvents, 
TSMutexCreate());
    +  //TSCont fetchCont = TSContCreate(handleHttpFetchIOEvents, NULL);
    +  TSContDataSet(fetchCont, static_cast<void *> (this));
    +
    +  // save server addr
    +  memmove((void *) &_serverAddr, (void *) serverAddr, sizeof (struct 
sockaddr));
    +
    +  // initiate request
    +  TSDebug(DEBUG_FETCH_TAG, "TSNetConnect()");
    +
    +  struct timeval tvStart;
    +  gettimeofday(&tvStart, NULL);
    +  _startTime = tvStart.tv_sec*1000 + tvStart.tv_usec/1000;
    +
    +  struct sockaddr_in tempServerAddr;
    +  memmove((void *) &tempServerAddr, (void *) &_serverAddr, sizeof (struct 
sockaddr));
    +  TSDebug(DEBUG_FETCH_TAG, "serverAddr: %s:%d", 
inet_ntoa(tempServerAddr.sin_addr), ntohs(tempServerAddr.sin_port) );
    +  _hcTimeout = TSContSchedule(fetchCont, _hcTimeoutSecond * 1000, 
TS_THREAD_POOL_DEFAULT);
    +  _connAction = TSNetConnect(fetchCont, (const struct sockaddr *) 
&_serverAddr);
    +
    +}
    +
    +/**********************************************************/
    +void
    +HttpFetch::parseResponse()
    +{
    +  TSIOBufferBlock block;
    +  TSParseResult pr = TS_PARSE_CONT;
    +  int64_t avail = 0;
    +  char *start = NULL;
    +  char *initialStart = NULL;
    +
    +  TSDebug(DEBUG_FETCH_TAG, "Entering parse_response");
    +
    +  block = TSIOBufferReaderStart(_respIOBufReader);
    +
    +  if (!_respInfo->headerParsed) {
    +    while ((pr == TS_PARSE_CONT) && (block != NULL)) {
    +      initialStart = start = (char *) TSIOBufferBlockReadStart(block, 
_respIOBufReader, &avail);
    +      if (avail > 0) {
    +        pr = TSHttpHdrParseResp(_respInfo->parser, _respInfo->buf, 
_respInfo->http_hdr_loc, (const char **) &start, (const char *) (start + 
avail));
    +        _responseHeaders.append(initialStart, start - initialStart);
    +      }
    +      block = TSIOBufferBlockNext(block);
    +    }
    +    // update avail
    +    if (start && initialStart) {
    +      avail -= (start - initialStart);
    +    }
    +    if (pr != TS_PARSE_CONT) {
    +      _respInfo->status = TSHttpHdrStatusGet(_respInfo->buf, 
_respInfo->http_hdr_loc);
    +      _responseStatus = _respInfo->status;
    +      _respInfo->headerParsed = true;
    +      TSDebug(DEBUG_FETCH_TAG, "HTTP Status: %d", _respInfo->status);
    +    }
    +  }
    +
    +  if (_respInfo->headerParsed) {
    +    if (avail && start) { // if bytes left from header parsing, get those
    +      _responseBody.append(start, avail);
    +      if(block) {
    +        block = TSIOBufferBlockNext(block);
    +      }
    +    }
    +
    +    while (block != NULL) {
    +      start = (char *) TSIOBufferBlockReadStart(block, _respIOBufReader, 
&avail);
    +      if (avail > 0) {
    +        _responseBody.append(start, avail);
    +      }
    +      block = TSIOBufferBlockNext(block);
    +    }
    +  }
    +  TSDebug(DEBUG_FETCH_TAG, "Leaving parseResponse");
    +}
    +
    +
    +/**********************************************************/
    +int
    +HttpFetch::handleIOEvent(TSCont cont, TSEvent event, void *edata)
    +{
    +  int64_t avail;
    +  bool bCleanUp = false; // free everything when transaction is complete
    +
    +
    +  TSDebug(DEBUG_FETCH_TAG, "Entering handleIOEvent");
    +
    +  switch (event) {
    +  case TS_EVENT_NET_CONNECT: // connected to server
    +    TSDebug(DEBUG_FETCH_TAG, "Connected (maybe)");
    +    _connAction = NULL;
    +    _respInfo = createResponseInfo();
    +    _reqInfo = createRequestInfo();
    +
    +    _reqIOBuf = TSIOBufferCreate();
    +    _reqIOBufReader = TSIOBufferReaderAlloc(_reqIOBuf);
    +    _respIOBuf = TSIOBufferCreate();
    +    _respIOBufReader = TSIOBufferReaderAlloc(_respIOBuf);
    +
    +    TSHttpHdrPrint(_reqInfo->buf, _reqInfo->http_hdr_loc, _reqIOBuf);
    +    TSIOBufferWrite(_reqIOBuf, "\r\n", 2);
    +
    +    _vConn = static_cast<TSVConn> (edata); // get connection
    +
    +    _rVIO = TSVConnRead(_vConn, cont, _respIOBuf, INT64_MAX);
    +
    +    TSDebug(DEBUG_FETCH_TAG, "Writing %ld bytes", 
TSIOBufferReaderAvail(_reqIOBufReader));
    +    _wVIO = TSVConnWrite(_vConn, cont, _reqIOBufReader, 
TSIOBufferReaderAvail(_reqIOBufReader));
    +    break;
    +  case TS_EVENT_NET_CONNECT_FAILED:
    +    TSDebug(DEBUG_FETCH_TAG, "Connect failed");
    +    _connAction = NULL;
    +    TSActionCancel(_hcTimeout);
    +    _hcTimeout = NULL;
    +    _result = FAILURE;
    +    break;
    +  case TS_EVENT_ERROR:
    +    TSDebug(DEBUG_FETCH_TAG, "Error event");
    --- End diff --
    
    Cancel `_hcTimeout`?


Issue Time Tracking
-------------------

    Worklog Id:     (was: 26924)
    Time Spent: 7h  (was: 6h 50m)

> ATS CARP Plugin
> ---------------
>
>                 Key: TS-4723
>                 URL: https://issues.apache.org/jira/browse/TS-4723
>             Project: Traffic Server
>          Issue Type: New Feature
>          Components: Plugins
>            Reporter: Eric Schwartz
>            Assignee: Eric Schwartz
>             Fix For: 7.0.0
>
>          Time Spent: 7h
>  Remaining Estimate: 0h
>
> Open sourcing this plugin we use internally within Yahoo in place of 
> hierarchical caching.
> CARP is a plugin that allows you to group a bunch of ATS hosts into a cluster 
> and share cache space across the entire group. This is done with consistent 
> hashing on the object URL to generate an "owner" node in the cluster. 
> Requests to any other node in the cluster will be forwarded on to the 
> corresponding owner. More info in the README.
> Difference from internal version of note:
> I've ripped out some code we weren't entirely sure we could open source 
> because of a hash function. If it turns out that we can open source this, 
> I'll do so. The CarpHashAlgorithm class is meant to be extensible, so any 
> consistent hash function can replace it. The function included here is pretty 
> straightforward but not what we use in production, so just wanted to use that 
> caveat.
> One last caveat:
> You'll see some code and documentation in here for object replication. This 
> is something I added recently to CARP that allows you to specify an object be 
> replicated a certain number of times in the cluster. This is useful if you 
> have a network partition or if you're performing some sort of update. When an 
> object's primary owner is unreachable, a node in the cluster can go to the 
> secondary owner if it's available rather than having to fall all the way back 
> to origin. While I've done some initial testing on this with my own cluster 
> of hosts, it's not been tested in production so use at your own risk for now. 
> I'll be sure to keep the open source community informed on the progress of 
> our tests with this feature.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to