File: precommit.c

package info (click to toggle)
diablo 1.16.test2-1
  • links: PTS
  • area: non-free
  • in suites: slink
  • size: 1,504 kB
  • ctags: 1,603
  • sloc: ansic: 17,654; perl: 2,054; sh: 260; csh: 118; makefile: 73
file content (166 lines) | stat: -rw-r--r-- 4,162 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166

/*
 * LIB/PRECOMMIT.C	- Precommit caching
 *
 */

#include "defs.h"

Prototype void InitPreCommit(void);
Prototype int PreCommit(const char *msgid, int postMode);
Prototype int SetPreCommitExpire(int pcex);

#define PC_HSIZE	8192	/* times sizeof(hash_t) */
#define PC_HMASK	(PC_HSIZE - 1)
#define PC_EXPIRE	30	/* 30 second expiration	*/

typedef struct pchash_t {
    hash_t	pc_Hash;	/* hash code		*/
    time_t	pc_Time;	/* time of entry	*/
    pid_t	pc_Pid;		/* process id, -1 if post commit */
} pchash_t;

pchash_t *PCHAry;
int	PCFd = -1;
int	PCExpire = PC_EXPIRE;		/* 30 second default	*/
int	PCPostExpire = PC_EXPIRE * 20;	/* 10 minute default	*/
int	PCPid = -1;

int 
SetPreCommitExpire(int pcex)
{
    int oex = PCExpire;
    PCExpire = pcex;
    PCPostExpire = PCExpire * 20;
    return(oex);
}

/*
 * InitPreCommit() is called by the master diablo to initialize any 
 *		   server-private (but inherited on fork) shared memory.
 *
 *		   We generate a private shared memory segment which is
 *		   mapped, then immediately removed.  The map is inherited
 *		   on fork.  If we don't remove it now, shm segments may
 *		   build up on the machine.
 *
 *		   NOTE: InitPreCommit() may not open() any descriptors because
 *		   our code is not designed to deal with the shared lseek
 *		   for the descriptor on fork.
 */

void
InitPreCommit(void)
{
#if USE_PCOMMIT_SHM
    int sid = shmget(IPC_PRIVATE, PC_HSIZE * sizeof(pchash_t), SHM_R|SHM_W);
    struct shmid_ds ds;

    if (sid < 0) {
	syslog(LOG_CRIT, "sysv shared memory alloc failed, is your machine configured with a high enough maximum segment size?");
	exit(1);
    }

    PCHAry = (pchash_t *)shmat(sid, NULL, SHM_R|SHM_W);

    if (shmctl(sid, IPC_STAT, &ds) < 0 || shmctl(sid, IPC_RMID, &ds) < 0) {
	syslog(LOG_CRIT, "sysv shmctl stat/rmid failed");
	exit(1);
    }
    if (PCHAry == (pchash_t *)-1) {
	PCHAry = NULL;
	syslog(LOG_CRIT, "sysv shared memory map failed");
	exit(1);
    }
#endif
}

int
PreCommit(const char *msgid, int postMode)
{
    int r = 0;

#if DO_PCOMMIT_POSTCACHE == 0
    /*
     * This option is turned on by default.  If it is 
     * off, do not write the precommit cache to post-cache
     * history lookup hits.
     */
    if (postMode)
	return(0);
#endif

    if (PCExpire == 0)
	return(0);

    if (PCPid == (pid_t)-1)
	PCPid = getpid();

    if (PCHAry == NULL) {
#if USE_PCOMMIT_SHM
	syslog(LOG_CRIT, "unable to initialize precommit cache");
	exit(1);
#else
	struct stat st;

	PCFd = xopen(O_RDWR|O_CREAT, 0644, "%s/pcommit.cache", NewsHome);

	if (PCFd >= 0 && fstat(PCFd, &st) == 0) {
	    int prot = PROT_READ | (USE_PCOMMIT_RW_MAP * PROT_WRITE);
	    if (st.st_size < PC_HSIZE * sizeof(pchash_t))
		ftruncate(PCFd, PC_HSIZE * sizeof(pchash_t));
	    PCHAry = xmap(NULL, PC_HSIZE * sizeof(pchash_t), prot, MAP_SHARED, PCFd, 0);
	}
#endif
    }
    if (PCHAry == NULL && PCFd >= 0) {
	close(PCFd);
	PCFd = -1;
    }
    if (PCHAry) {
	hash_t hv = hhash(msgid);
	int i = (hv.h1 ^ hv.h2) & PC_HMASK;
	pchash_t *pc = &PCHAry[i];
	time_t t = time(NULL);
	int32 dt = t - pc->pc_Time;

	if (pc->pc_Hash.h1 == hv.h1 && 
	    pc->pc_Hash.h2 == hv.h2 &&
	    dt >= 0 && 
	    ((dt < PCExpire && pc->pc_Pid != PCPid) ||
	    (dt < PCPostExpire && pc->pc_Pid == (pid_t)-1))
	) {
	    /*
	     * collision.  Return -1.  If we are posting a history cache
	     * hit/commit, change the pid to -1, which lengthens the expire
	     * time.  We can do this because the message-id is already in
	     * the history file.
	     */
	    r = -1;
#if USE_PCOMMIT_RW_MAP && DO_PCOMMIT_POSTCACHE
	    if (postMode && pc->pc_Pid != (pid_t)-1) {
		pc->pc_Pid = (pid_t)-1;
	    }
#endif
	} else {
	    pchash_t npc;
	    /*
	     * enter new info, we don't care about collisions
	     *
	     * postMode is set only when we are using the precommit
	     * cache as a post-commit 'in the history file' cache.
	     */
	    npc.pc_Hash = hv;
	    npc.pc_Time = t - 1;
	    npc.pc_Pid = (postMode) ? (pid_t)-1 : PCPid;
#if USE_PCOMMIT_RW_MAP
	    PCHAry[i] = npc;
#else
	    lseek(PCFd, i * sizeof(pchash_t), 0);
	    write(PCFd, &npc, sizeof(npc));
#endif
	}
    }
    return(r);
}