Browse Source

most likely found a bug in the glibc tdelete implementation...don't have the mood of building a simple testcase for reporting. Maybe I do when I have implemented my own trees.

release0.1.5
Georg Hopp 12 years ago
parent
commit
417b9f6d8f
  1. 48
      TODO
  2. 2
      include/http/response.h
  3. 10
      src/asset/asset.c
  4. 29
      src/asset/pool.c
  5. 57
      src/hash/delete.c
  6. 8
      src/hash/get.c
  7. 18
      src/hash/interface/hashable.c
  8. 2
      src/http/message.c
  9. 7
      src/http/response/asset.c
  10. 29
      src/http/worker/get_asset.c
  11. 8
      src/http/writer/write.c
  12. 12
      src/server/handle_accept.c
  13. 2
      src/server/run.c

48
TODO

@ -27,3 +27,51 @@ VERY BIG TODO:
* also concurrent connection don't seem to make a problem.
* keep-alive alone again don't seem to be a problem...
!!!! if both are active something is screwed up.... !!!!
- at least some of the problems result in something that I think
is a bug in the glibc implementation of tdelete.
Under some circumstances tdelete does not search the whole tree.
Here comes some debug output of the code...
This shows a code fragment that tries to remove a no longer
needed asset from the asset_pool.
DEBUG: pool release asset --./assets/image/waldschrat.jpg--
Twalk over all elements in the tree:
DEBUG: ./assets/image/waldschrat.jpg(1910357807899405601) => 0xe378a8
DEBUG: ./assets/js/jquery.js(10519512221325982142) => 0x10d3638
Output of each call to tDelete comparison function:
(Notice that the searched asset hash was in the previous Twalk.
DEBUG: search asset hash: 1910357807899405601
DEBUG: found: 10519512221325982142, key: ./assets/js/jquery.js
DEBUG: !!!!! NOT FOUND !!!!!!!
DEBUG: find results in (nil)
Repeated 2 times if non was found...
DEBUG: search asset hash: 1910357807899405601
DEBUG: found: 10519512221325982142, key: ./assets/js/jquery.js
DEBUG: !!!!! NOT FOUND !!!!!!!
DEBUG: find results in (nil)
DEBUG: search asset hash: 1910357807899405601
DEBUG: found: 10519512221325982142, key: ./assets/js/jquery.js
DEBUG: !!!!! NOT FOUND !!!!!!!
DEBUG: find results in (nil)
===
Again a twalk over all elements...
DEBUG: ./assets/image/waldschrat.jpg(1910357807899405601) => 0xe378a8
DEBUG: ./assets/js/jquery.js(10519512221325982142) => 0x10d3638
Final statement...
DEBUG delete 0xe378a8, parent was (nil)
So, it looks like I should build my own tree implementation...
well in fact it seems that I have to!

2
include/http/response.h

@ -51,7 +51,7 @@ HttpResponse httpResponseMe();
HttpResponse httpResponseLoginForm();
HttpResponse httpResponseRandval(time_t, int);
HttpResponse httpResponseSession(Session);
HttpResponse httpResponseAsset(Asset);
HttpResponse httpResponseAsset(const char *, size_t);
#endif // __HTTP_RESPONSE_H__

10
src/asset/asset.c

@ -20,6 +20,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// for debug
#include <stdio.h>
#include <stdarg.h>
// for mmap
@ -97,9 +101,13 @@ assetCtor(void * _this, va_list * params)
NULL, this->size, PROT_READ, MAP_PRIVATE, this->handle, 0);
if (MAP_FAILED == this->data) {
close(this->handle);
return -1;
}
printf("DEBUG file mapped from %p to %p\n",
this->data, this->data + this->size);
this->ref_count = 1;
return 0;
@ -112,7 +120,7 @@ static void assetDtor(void * _this) {
munmap(this->data, this->size);
}
if (0 != this->handle) {
if (0 < this->handle) {
close(this->handle);
}
}

29
src/asset/pool.c

@ -20,6 +20,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// for debugging
#include <stdio.h>
// for size_t
#include <sys/types.h>
@ -44,6 +47,8 @@ assetPoolGet(const char * path, size_t npath)
{
Asset asset = NULL;
printf("DEBUG: pool get asset --%s--\n", path);
if (NULL == asset_pool) {
asset_pool = new(Hash);
} else {
@ -52,9 +57,12 @@ assetPoolGet(const char * path, size_t npath)
if (NULL == asset) {
asset = new(Asset, path, npath);
printf("DEBUG create asset %p\n", asset);
hashAdd(asset_pool, asset);
} else {
printf("DEBUG found asset %p\n", asset);
asset->ref_count++;
printf("DEBUG increase ref_count to %zu\n", asset->ref_count);
}
return asset;
@ -63,19 +71,22 @@ assetPoolGet(const char * path, size_t npath)
size_t
assetPoolRelease(Asset asset)
{
if (asset->ref_count <= 1) {
hashDelete( asset_pool, asset->fname, asset->nfname);
printf("DEBUG: pool release asset --%s--\n", asset->fname);
if (NULL != asset) {
delete(asset);
}
return 0;
} else {
if (asset->ref_count > 1) {
asset->ref_count--;
printf("DEBUG decrease ref_count to %zu\n", asset->ref_count);
return asset->ref_count;
}
if (NULL != asset) {
Asset found = (Asset)hashDelete(
asset_pool, asset->fname, asset->nfname);
printf("DEBUG delete %p, parent was %p\n", asset, found);
delete(asset);
}
return 0;
}
void

57
src/hash/delete.c

@ -20,9 +20,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <search.h>
#include <sys/types.h>
#include "asset.h"
#include "hash.h"
#include "utils/hash.h"
@ -31,25 +34,61 @@ inline
int
hashDeleteComp(const void * a, const void * b)
{
if (_Asset == GET_CLASS(b)) {
Asset data = (Asset)b;
printf("DEBUG: search asset hash: %lu\n",
*(const unsigned long*)a);
printf("DEBUG: found: %lu, key: %s\n",
data->hash, data->fname);
}
return hashableGetHash((void*)b) - *(const unsigned long*)a;
}
void
action(const void *nodep, const VISIT which, const int depth)
{
void * datap = *(void **)nodep;
if (_Asset == GET_CLASS(datap)) {
Asset data = (Asset)datap;
switch (which) {
case preorder:
break;
case postorder:
printf("DEBUG: %s(%lu) => %p\n", data->fname, data->hash, data);
break;
case endorder:
break;
case leaf:
printf("DEBUG: %s(%lu) => %p\n", data->fname, data->hash, data);
break;
}
}
}
void *
hashDelete(Hash this, const char * search, size_t nsearch)
{
unsigned long hash = sdbm((const unsigned char *)search, nsearch);
void ** _found = tfind(&hash, &(this->root), hashDeleteComp);
void * found;
void * found = NULL;
int count = 0;
if (NULL != _found) {
found = *_found;
} else {
found = NULL;
twalk(this->root, action);
while (found == NULL && count < 3) {
found = tdelete(&hash, &(this->root), hashDeleteComp);
if (found == NULL) {
puts("DEBUG: !!!!! NOT FOUND !!!!!!!");
void * found = hashGet(this, search, nsearch);
printf("DEBUG: find results in %p\n", found);
}
count++;
}
puts("===");
twalk(this->root, action);
tdelete(&hash, &(this->root), hashDeleteComp);
return (NULL != found)? found : NULL;
return found;
}
// vim: set ts=4 sw=4:

8
src/hash/get.c

@ -20,6 +20,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <search.h>
#include <sys/types.h>
@ -37,10 +39,10 @@ hashGetComp(const void * a, const void * b)
void *
hashGet(Hash this, const char * search, size_t nsearch)
{
unsigned long hash = sdbm((const unsigned char *)search, nsearch);
void * found = tfind(&hash, &(this->root), hashGetComp);
unsigned long hash = sdbm((const unsigned char *)search, nsearch);
void ** found = tfind(&hash, &(this->root), hashGetComp);
return (NULL != found)? *(void**)found : NULL;
return (NULL != found)? *found : NULL;
}
// vim: set ts=4 sw=4:

18
src/hash/interface/hashable.c

@ -37,7 +37,23 @@ hashableGetHash(void * hashable)
{
unsigned long ret;
RETCALL(hashable, Hashable, getHash, ret);
//RETCALL(hashable, Hashable, getHash, ret);
do {
struct i_Hashable * iface;
//_CALL(GET_CLASS(hashable), Hashable, getHash);
do {
class_ptr class = GET_CLASS(hashable);
iface = (struct i_Hashable *)IFACE_GET(class, &i_Hashable);
while ((NULL == iface || NULL == iface->getHash) && HAS_PARENT(class)) {
class = class->parent;
iface = (struct i_Hashable *)IFACE_GET(class, &i_Hashable);
}
assert(NULL != iface->getHash);
} while(0);
ret = iface->getHash(hashable);
} while(0);
return ret;
}

2
src/http/message.c

@ -65,6 +65,8 @@ httpMessageDtor(void * _this)
MEM_FREE(this->body);
} else {
assetPoolRelease(this->asset);
this->asset = NULL;
this->body = NULL;
}
}

7
src/http/response/asset.c

@ -55,10 +55,15 @@
HttpResponse
httpResponseAsset(Asset asset)
httpResponseAsset(const char * fname, size_t nfname)
{
HttpResponse response;
HttpMessage message;
Asset asset = assetPoolGet(fname, nfname);
if (NULL == asset) {
return NULL;
}
response = new(HttpResponse, "HTTP/1.1", 200, "OK");
message = (HttpMessage)response;

29
src/http/worker/get_asset.c

@ -41,7 +41,6 @@ httpWorkerGetAsset(
size_t nmatch;
HttpHeader header;
HttpMessage message;
Asset asset;
size_t nfname = strlen(fname);
@ -58,30 +57,24 @@ httpWorkerGetAsset(
nmatch = (header->nvalue)[0];
}
asset = assetPoolGet(fname, nfname);
message = (HttpMessage)httpResponseAsset(fname, nfname);
if (NULL == asset) {
if (NULL == message) {
return (HttpMessage)httpResponse404();
}
if (asset->netag == nmatch
&& 0 == memcmp(asset->etag, match, asset->netag)) {
assetPoolRelease(asset);
if (message->asset->netag == nmatch
&& 0 == memcmp(message->asset->etag, match, nmatch)) {
HttpMessage new_message;
return (HttpMessage)httpResponse304(
asset->mime_type, asset->nmime_type,
asset->etag, asset->netag,
asset->mtime, asset->nmtime);
}
new_message = (HttpMessage)httpResponse304(
message->asset->mime_type, message->asset->nmime_type,
message->asset->etag, message->asset->netag,
message->asset->mtime, message->asset->nmtime);
message = (HttpMessage)httpResponseAsset(asset);
delete(message);
if (NULL == message) {
// here we should be somewhat more care about what causes
// the message to be NULL... here this could be also a
// 404 not found....
assetPoolRelease(asset);
message = (HttpMessage)httpResponse500();
return new_message;
}
return message;

8
src/http/writer/write.c

@ -117,12 +117,8 @@ httpWriterWrite(void * _this, Stream st)
* By the way, the same is true for reading,
* so to say, the parser.
*/
// cont = 0;
// break;
/* to go a step further...we send it to the
* poll cicle again... */
return -1;
cont = 0;
break;
}
if (this->written >= this->nheader + this->current->nbody) {

12
src/server/handle_accept.c

@ -44,9 +44,10 @@ serverHandleAccept(Server this, unsigned int i)
}
acc = socketAccept((0 == i)? this->sock : this->sockSSL, &remoteAddr);
socketNonblock(acc);
if (-1 != acc->handle) {
if (NULL != acc && -1 != acc->handle) {
socketNonblock(acc);
switch(i) {
case 0:
// no SSL
@ -82,21 +83,24 @@ serverHandleAccept(Server this, unsigned int i)
delete(acc);
switch(errno) {
case EAGAIN:
case EAGAIN|EWOULDBLOCK:
case EINTR:
loggerLog(this->logger,
LOGGER_DEBUG,
"server accept blocks");
return -1;
break;
default:
loggerLog(this->logger,
LOGGER_DEBUG,
"server accept error");
return -2;
break;
}
}
return (acc)? acc->handle : -1;
return acc->handle;
}
// vim: set ts=4 sw=4:

2
src/server/run.c

@ -51,7 +51,7 @@ serverRun(Server this)
* handle accept
*/
if (0 != ((this->fds)[0].revents & POLLIN)) {
if (-1 == serverHandleAccept(this, 0)) {
if (0 > serverHandleAccept(this, 0)) {
events--;
}
}

Loading…
Cancel
Save