/* * Copyright (c) 2019 TAOS Data, Inc. * * This program is free software: you can use, redistribute, and/or modify * it under the terms of the GNU Affero General Public License, version 3 * or later ("AGPL"), as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include "tnote.h" taosNoteInfo m_HttpNote; taosNoteInfo m_TscNote; int taosOpenNoteWithMaxLines(char *fn, int maxLines, int maxNoteNum, taosNoteInfo * pNote); void taosInitNote(int numOfNoteLines, int maxNotes, char* lable) { taosNoteInfo * pNote = NULL; char temp[128] = { 0 }; if (strcasecmp(lable, "http_note") == 0) { pNote = &m_HttpNote; sprintf(temp, "%s/httpnote", tsLogDir); } else if (strcasecmp(lable, "tsc_note") == 0) { pNote = &m_TscNote; sprintf(temp, "%s/tscnote-%d", tsLogDir, getpid()); } else { return; } memset(pNote, 0, sizeof(taosNoteInfo)); pNote->taosNoteFileNum = 1; //pNote->taosNoteMaxLines = 0; //pNote->taosNoteLines = 0; //pNote->taosNoteFlag = 0; pNote->taosNoteFd = -1; //pNote->taosNoteOpenInProgress = 0; if (taosOpenNoteWithMaxLines(temp, numOfNoteLines, maxNotes, pNote) < 0) fprintf(stderr, "failed to init note file\n"); taosNotePrint(pNote, "=================================================="); taosNotePrint(pNote, "=================== new note ==================="); taosNotePrint(pNote, "=================================================="); } void taosCloseNoteByFd(int oldFd, taosNoteInfo * pNote); bool taosLockNote(int fd, taosNoteInfo * pNote) { if (fd < 0) return false; if (pNote->taosNoteFileNum > 1) { int ret = (int)(flock(fd, LOCK_EX | LOCK_NB)); if (ret == 0) { return true; } } return false; } void taosUnLockNote(int fd, taosNoteInfo * pNote) { if (fd < 0) return; if (pNote->taosNoteFileNum > 1) { flock(fd, LOCK_UN | LOCK_NB); } } void *taosThreadToOpenNewNote(void *param) { char name[NOTE_FILE_NAME_LEN * 2]; taosNoteInfo * pNote = (taosNoteInfo *)param; pNote->taosNoteFlag ^= 1; pNote->taosNoteLines = 0; sprintf(name, "%s.%d", pNote->taosNoteName, pNote->taosNoteFlag); umask(0); int fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO); if (fd < 0) { return NULL; } taosLockNote(fd, pNote); (void)lseek(fd, 0, SEEK_SET); int oldFd = pNote->taosNoteFd; pNote->taosNoteFd = fd; pNote->taosNoteLines = 0; pNote->taosNoteOpenInProgress = 0; taosNotePrint(pNote, "=============== new note is opened ============="); taosCloseNoteByFd(oldFd, pNote); return NULL; } int taosOpenNewNote(taosNoteInfo * pNote) { pthread_mutex_lock(&pNote->taosNoteMutex); if (pNote->taosNoteLines > pNote->taosNoteMaxLines && pNote->taosNoteOpenInProgress == 0) { pNote->taosNoteOpenInProgress = 1; taosNotePrint(pNote, "=============== open new note =================="); pthread_t pattern; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_create(&pattern, &attr, taosThreadToOpenNewNote, (void*)pNote); pthread_attr_destroy(&attr); } pthread_mutex_unlock(&pNote->taosNoteMutex); return pNote->taosNoteFd; } bool taosCheckNoteIsOpen(char *noteName, taosNoteInfo * pNote) { /* int exist = access(noteName, F_OK); if (exist != 0) { return false; } */ int fd = open(noteName, O_WRONLY | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO); if (fd < 0) { fprintf(stderr, "failed to open note:%s reason:%s\n", noteName, strerror(errno)); return true; } if (taosLockNote(fd, pNote)) { taosUnLockNote(fd, pNote); close(fd); return false; } else { close(fd); return true; } } void taosGetNoteName(char *fn, taosNoteInfo * pNote) { if (pNote->taosNoteFileNum > 1) { for (int i = 0; i < pNote->taosNoteFileNum; i++) { char fileName[NOTE_FILE_NAME_LEN]; sprintf(fileName, "%s%d.0", fn, i); bool file1open = taosCheckNoteIsOpen(fileName, pNote); sprintf(fileName, "%s%d.1", fn, i); bool file2open = taosCheckNoteIsOpen(fileName, pNote); if (!file1open && !file2open) { sprintf(pNote->taosNoteName, "%s%d", fn, i); return; } } } if (strlen(fn) < NOTE_FILE_NAME_LEN) { strcpy(pNote->taosNoteName, fn); } } int taosOpenNoteWithMaxLines(char *fn, int maxLines, int maxNoteNum, taosNoteInfo * pNote) { char name[NOTE_FILE_NAME_LEN * 2] = "\0"; struct stat notestat0, notestat1; int size; pNote->taosNoteMaxLines = maxLines; pNote->taosNoteFileNum = maxNoteNum; taosGetNoteName(fn, pNote); if (strlen(fn) > NOTE_FILE_NAME_LEN * 2 - 2) { fprintf(stderr, "the len of file name overflow:%s\n", fn); return -1; } strcpy(name, fn); strcat(name, ".0"); // if none of the note files exist, open 0, if both exists, open the old one if (stat(name, ¬estat0) < 0) { pNote->taosNoteFlag = 0; } else { strcpy(name, fn); strcat(name, ".1"); if (stat(name, ¬estat1) < 0) { pNote->taosNoteFlag = 1; } else { pNote->taosNoteFlag = (notestat0.st_mtime > notestat1.st_mtime) ? 0 : 1; } } char noteName[NOTE_FILE_NAME_LEN * 2] = "\0"; sprintf(noteName, "%s.%d", pNote->taosNoteName, pNote->taosNoteFlag); pthread_mutex_init(&pNote->taosNoteMutex, NULL); umask(0); pNote->taosNoteFd = open(noteName, O_WRONLY | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO); if (pNote->taosNoteFd < 0) { fprintf(stderr, "failed to open note file:%s reason:%s\n", noteName, strerror(errno)); return -1; } taosLockNote(pNote->taosNoteFd, pNote); // only an estimate for number of lines struct stat filestat; if (fstat(pNote->taosNoteFd, &filestat) < 0) { fprintf(stderr, "failed to fstat note file:%s reason:%s\n", noteName, strerror(errno)); return -1; } size = (int)filestat.st_size; pNote->taosNoteLines = size / 60; lseek(pNote->taosNoteFd, 0, SEEK_END); return 0; } void taosNotePrint(taosNoteInfo * pNote, const char * const format, ...) { va_list argpointer; char buffer[MAX_NOTE_LINE_SIZE+2]; int len; struct tm Tm, *ptm; struct timeval timeSecs; time_t curTime; gettimeofday(&timeSecs, NULL); curTime = timeSecs.tv_sec; ptm = localtime_r(&curTime, &Tm); #ifndef LINUX len = sprintf(buffer, "%02d/%02d %02d:%02d:%02d.%06d 0x%lld ", ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (int)timeSecs.tv_usec, taosGetPthreadId()); #else len = sprintf(buffer, "%02d/%02d %02d:%02d:%02d.%06d %lx ", ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (int)timeSecs.tv_usec, pthread_self()); #endif va_start(argpointer, format); len += vsnprintf(buffer + len, MAX_NOTE_LINE_SIZE - len, format, argpointer); va_end(argpointer); if (len >= MAX_NOTE_LINE_SIZE) len = MAX_NOTE_LINE_SIZE - 2; buffer[len++] = '\n'; buffer[len] = 0; if (pNote->taosNoteFd >= 0) { twrite(pNote->taosNoteFd, buffer, (unsigned int)len); if (pNote->taosNoteMaxLines > 0) { pNote->taosNoteLines++; if ((pNote->taosNoteLines > pNote->taosNoteMaxLines) && (pNote->taosNoteOpenInProgress == 0)) taosOpenNewNote(pNote); } } } void taosCloseNote(taosNoteInfo * pNote) { taosCloseNoteByFd(pNote->taosNoteFd, pNote); } void taosCloseNoteByFd(int fd, taosNoteInfo * pNote) { if (fd >= 0) { taosUnLockNote(fd, pNote); close(fd); } }